崔毅东 C++程序设计入门(上) 第5单元:万类霜天竞自由 – 对象和类的更多内容 笔记

第01节:不可变对象、不可变类;避免多次声明

在这里插入图片描述
在这里插入图片描述在这里插入图片描述
Date1.h

class Date
{
public:
  Date(int newYear, int newMonth, int newDay);
  //Date(int , int , int );
  int getYear();
  void setYear(int newYear);

private:
  int year;
  int month;
  int day;
};

Date1.cpp

#include "Date1.h"

Date::Date(int newYear, int newMonth, int newDay)
{
  year = newYear;
  month = newMonth;
  day = newDay;
}

int Date::getYear()
{
  return year;
}

void Date::setYear(int newYear)
{
  year = newYear;
}

Person1.h

#include "Date1.h"
class Person
{
public:
	Person(int id, int year, int month, int day);
	Person(Person &);//拷贝构造函数
	int getId();
	Date * getBirthDate();

private:
	int id;
	Date *birthDate;
	

};

Person1.cpp

#include "Person1.h"
Person::Person(int id, int year, int month, int day)
{
	this -> id = id;
	birthDate = new Date(year, month, day);
}
Person :: Person(Person &person)
{
	id = Person.id;
	Date *p = person.getBirthDate();
	birthDate = new Date(*p);
}
int Person::getId()
{
  return id;
}

Date * Person::getBirthDate()
{
  return birthDate; // Return the pointer of the object
}

TestPerson1.cpp

#include <iostream>
#include "Person1.h"
#include "Date1.h"  // Person1.h已经包含Date1.h 所以这里重复定义
using namespace std;
int main()
{
  Person person(111223333, 1970, 5, 3);
  Date *pDate = person.getBirthDate();
  pDate -> setYear(2010);
  cout << person.getBirthDate() -> getYear() << endl;
  return 0;
}

在这里插入图片描述
解决方案1

#ifndef DATE1_H
#define DATE1_H 
class Date
{
public:
  Date(int newYear, int newMonth, int newDay);
  //Date(int , int , int );
  int getYear();
  void setYear(int newYear);

private:
  int year;
  int month;
  int day;
};
#endif

解决方案2

#pragma once
class Date
{
public:
  Date(int newYear, int newMonth, int newDay);
  //Date(int , int , int );
  int getYear();
  void setYear(int newYear);

private:
  int year;
  int month;
  int day;
};

U05S01 - 不可变对象与Thread-safe
什么是 thread-safe?
不可变对象一定是 thread-safe 的吗?为什么?
答:1、Thread-safe:在多线程环境下,多个线程在访问共享数据时,为了保证该数据的安全而做出的一种承诺或者机制;
2、不可变对象本身有两层含义,一个是共享的数据(如果有)是只读的,另一个是与生俱来的线程安全性。可以说不可变对象是天生Thread-safe;(by m15522962525)

第02节:实例成员与静态成员

在这里插入图片描述
static 关键字将sq 限定在fun中,main函数无法调用
在这里插入图片描述
静态变量在静态区 所有共有而实例变量在栈区
Circle5.h

#ifndef CIRCLE_H
#define CIRCLE_H

class Circle
{
public:
  Circle();
  Circle(double);
  double getArea();
  double getRadius();
  void setRadius(double);
  
  static int getNumberOfObjects(); //static function

private:
  double radius;
  
  static int numberOfObjects;      //static variable 
};

#endif

Circle5.cpp

#include "Circle5.h"

// What will happen when commenting out the next line?
int Circle::numberOfObjects = 0;//静态变量只能在所有函数之外初始化

// Construct a circle object
Circle::Circle()
{
  radius = 1;
  numberOfObjects++;
}

// Construct a circle object
Circle::Circle(double radius)
{
  this->radius = radius;
  numberOfObjects++;
}

// Return the area of this circle
double Circle::getArea()
{
  return radius * radius * 3.14159;
}

// Return the radius of this circle
double Circle::getRadius()
{
  return radius;
}

// Set a new radius
void Circle::setRadius(double radius)
{
  this->radius = (radius >= 0) ? radius : 0;
}

// Return the number of circle objects
int Circle::getNumberOfObjects()
{
  return numberOfObjects;
}

在这里插入图片描述在这里插入图片描述在这里插入图片描述
好的编程风格:在静态变量前加入类名+域分隔符
在这里插入图片描述

第03节:析构函数与友元

在这里插入图片描述在这里插入图片描述在这里插入图片描述
缺点:打破了封装性
友元函数:TestFriendFunction.cpp

#include <iostream>
using namespace std;

class Date 
{
  friend void p();

private:
  int year;
  int month;
  int day;
};

void p()
{
  Date date;
  date.year = 2000;
  cout << date.year;
}

int main()
{
  p();
  return 0;
}

友元类:
Date2.h

class Date
{
public:
  friend class AccessDate;

private:
  int year;
  int month;
  int day;
};

TestFriendClass.cpp

#include <iostream>
#include "Date2.h"
using namespace std;

class AccessDate
{
public:
  static void p()
  {
    Date birthDate;
    birthDate.year = 2000;
    cout << birthDate.year;
  }
};

int main()
{
  AccessDate::p();
  return 0;
}

U05S03 - 关于友元的一些问题

  1. 两个类可以互为友元类吗?如果你能举出例子就更好了

  2. 其它的面向对象编程语言中,有friend这种东西或者类似的东西吗?

  3. 一个类可以有友元,友元能够访问这个类中的私有/保护成员;那么,一个函数是否可以有友元,通过友元访问这个函数中的局部变量?
    答:1、可以的,代码如下:

class A{
public:
    friend class B;
};
class B{
public:
    friend class A;
};
int main(){
    return 0;
}

2、Java中没有这个概念;

3、函数的局部变量在进程没有运行到该函数时,其是不存在的。即便定义了友元,甚至是规定了访问方法,也是无济于事的。(by m15522962525)
U05S03 - 析构函数的问题
析构函数为啥不能有参数?

析构函数为啥不能有返回值?

假如析构函数可以有参数,也可以有返回值,会有什么后果? 大胆猜一猜,说说你的看法
答:析构用来释放内存的,如果有返回值,返回值要存放在哪里,参数的值要放在哪里?(by 小嘉学长)

第04节:拷贝构造函数

在这里插入图片描述
只有在定义时用=才调用拷贝构造函数
在这里插入图片描述
浅拷贝例子
Date.h

#ifndef DATE_H
#define DATE_H

class Date
{
public:
  Date(int newYear, int newMonth, int newDay);
  int getYear();
  void setYear(int newYear);

private:
  int year;
  int month;
  int day;
};

#endif

Date.cpp

#include "Date.h"

Date::Date(int newYear, int newMonth, int newDay)
{
  year = newYear;
  month = newMonth;
  day = newDay;
}

int Date::getYear()
{
  return year;
}

void Date::setYear(int newYear)
{
  year = newYear;
}

Person.h

#pragma once 
#include "Date.h"

class Person
{
public:
  Person(int id, int year, int month, int day);
  int getId();
  Date* getBirthDate(); // Return the pointer of the object

private:
  int id_;
  Date* birthDate ; // The pointer of the object
};

Person.cpp

#include "Person.h"

Person::Person(int id, int year, int month, int day)
{
  id_ = id;
  birthDate = new Date(year, month, day);
}

int Person::getId()
{
  return id_;
}

Date * Person::getBirthDate()
{
  return birthDate; // Return the pointer of the object
}

ShallowCopyDemo.cpp

#include <iostream>
#include "Person.h"
using namespace std;

void displayPerson(Person &person1, Person &person2)
{
  cout << "\tperson1 id: " << person1.getId() << endl;
  cout << "\tperson1 birth year: " <<
          person1.getBirthDate() -> getYear() << endl;
  cout << "\tperson2 id: " << person2.getId() << endl;
  cout << "\tperson2 birth year: " <<
          person2.getBirthDate() -> getYear() << endl;
}

int main()
{
  Person person1(111, 1970, 5, 3);
  Person person2(222, 2000, 11, 8); 

  cout << "After creating person1 and person2" << endl;
  displayPerson(person1, person2);

  person1 = Person(person2); // Copy person2 to person1

  cout << "\nAfter copying person2 to person1" << endl;
  displayPerson(person1, person2);

  person2.getBirthDate() -> setYear(1963);

  cout << "\nAfter modifying person2's birthDate" << endl;
  displayPerson(person1, person2);

  cout << "\n" << (person1.getBirthDate() == person2.getBirthDate());
  return 0;
}

在这里插入图片描述在这里插入图片描述
在这里插入图片描述
深拷贝
Person1.h

#include "Date1.h"

class Person
{
public:
  Person(int id, int year, int month, int day);
  Person(Person &);
  int getId();
  Date * getBirthDate(); // Return the pointer of the object

private:
  int id;
  Date *birthDate; // The pointer of the object
};

Person1.cpp

#include "Person1.h"

Person::Person(int id, int year, int month, int day)
{
  this -> id = id;
  birthDate = new Date(year, month, day);
}

Person::Person(Person &person)
{
  id = person.id;
  Date *p = person.getBirthDate();
  birthDate = new Date(*p);
}

int Person::getId()
{
  return id;
}

Date * Person::getBirthDate()
{
  return birthDate; // Return the pointer of the object
}

CustomCopyConstructor.cpp

#include <iostream>
#include "Person1.h"
using namespace std;

void displayPerson(Person &person1, Person &person2)
{
  cout << "\tperson1 id: " << person1.getId() << endl;
  cout << "\tperson1 birth year: " <<
    person1.getBirthDate() -> getYear() << endl;
  cout << "\tperson2 id: " << person2.getId() << endl;
  cout << "\tperson2 birth year: " <<
    person2.getBirthDate() -> getYear() << endl;
}

int main()
{
  Person person1(111, 1970, 5, 3);
  Person person2(person1);

  cout << "After creating person1 and person2" << endl;
  displayPerson(person1, person2);

  person2.getBirthDate() -> setYear(1963);

  cout << "\nAfter modifying person2's birthDate" << endl;
  displayPerson(person1, person2);
  
  cout << "\n\nperson1.birthDate == person2.birthDate:  " << boolalpha <<
          (person1.getBirthDate() == person2.getBirthDate()) << "\n\n";

  Person person3(111, 1970, 5, 3);
  Person person4 = person3;
  
  cout << "person3.birthDate =" <<
          reinterpret_cast<int> (person3.getBirthDate()) << endl;
  cout << "person4.birthDate =" << 
          reinterpret_cast<int> (person4.getBirthDate()) << endl;

  return 0;
}

在这里插入图片描述
U05S04 - 深/浅拷贝的神话传说老师参与
想必你被这一节跳来跳去的代码跳晕了吧?请往下看,你会更晕

到底啥是深/浅拷贝呢? 有一本书它名叫天方夜谭,神奇又好看,叙述的是阿拉伯的故事,到处都在流传…

话说你与你的好基友/蜜友外出探险:

你的好基友/蜜友拣了一神灯。Ta擦擦神灯,一个魔鬼从神灯中冒出来可以实现Ta的两个愿望。Ta说:1. 我要一山洞的财宝;2. 我要打开山洞的钥匙。

你也拣了一个神灯,擦擦神灯,一个魔鬼从神灯中冒出来可以实现你的两个愿望。你说:浅拷贝! 然后魔鬼给了你一把钥匙,能打开你好基友的山洞。。。你还剩下一个愿望。。。但是。。。最后你和你的好基友/蜜友因为争抢财宝而同归于尽

你也拣了一个神灯,擦擦神灯,一个魔鬼从神灯中冒出来可以实现你的两个愿望。你说:深拷贝! 然后魔鬼给了你另外一个山洞的财宝,给了你打开这个山洞的钥匙。。。。。。。。最后你和好基友/蜜友幸福滴生活在一起

第05节:示例分析

在这里插入图片描述
Course,h

#ifndef COURSE_H
#define COURSE_H

#include <string>
using namespace std;

class Course
{
public:
  Course(const string &name);
  string getName();
  void addStudent(const string &student);
  string * getStudents();
  int getNumberOfStudents();

private:
  string name;
  string students[100];
  int numberOfStudents;
};

#endif

Course.cpp

#include <iostream>
#include <cstdlib>
#include "Course.h"
using namespace std;

Course::Course(const string &name)
{
  numberOfStudents = 0;
  this -> name = name;
}

string Course::getName()
{
  return name;
}

void Course::addStudent(const string &student)
{
  if (numberOfStudents >= 100)
  {
    cout << "The maximum size of array exceeded" << endl;
    cout << "Program terminates now" << endl;
    exit(0);
  }

  students[numberOfStudents] = student;
  numberOfStudents++;
}

string * Course::getStudents()
{
  return students;
}

int Course::getNumberOfStudents()
{
  return numberOfStudents;
}

TestCourse.cpp

#include <iostream>
#include "Course.h"
using namespace std;

int main()
{
  Course course1("Data Structures");
  Course course2("Database Systems");

  course1.addStudent("Peter Jones");
  course1.addStudent("Brian Smith");
  course1.addStudent("Anne Kennedy");

  course2.addStudent("Peter Jones");
  course2.addStudent("Steve Smith");

  cout << "Number of students in course1: " <<
          course1.getNumberOfStudents() << "\n";
  string * students = course1.getStudents();
  for (int i = 0; i < course1.getNumberOfStudents(); i++)
    cout << students[i] << ", ";

  cout << "\nNumber of students in course2: " << 
          course2.getNumberOfStudents() << "\n";
  students = course2.getStudents();
  for (int i = 0; i < course2.getNumberOfStudents(); i++)
    cout << students[i] << ", ";

  return 0;
}

在这里插入图片描述
在这里插入图片描述在这里插入图片描述
StackOfIntegers.h

#ifndef STACK_H
#define STACK_H

class StackOfIntegers
{
public:
  StackOfIntegers();
  bool empty();
  int peek();
  int push(int value);
  int pop();
  int getSize();

private:
  int elements[100];
  int size;
};

#endif

StackOfIntegers.cpp

#include "StackOfIntegers.h"

StackOfIntegers::StackOfIntegers()
{
  size = 0;
}

bool StackOfIntegers::empty()
{
  return (size == 0);
}

int StackOfIntegers::peek()
{
    return elements[size - 1];
}

int StackOfIntegers::push(int value)
{
  //return elements[size++] = value;
  elements[size] = value;
  size++;
  return value;
}

int StackOfIntegers::pop()
{
// Following 3 lines is for debug usage  
  int t = elements[--size];
  elements[size] = -1;
  return t;  
//  return elements[--size];
}

int StackOfIntegers::getSize()
{
  return size;
}

TestStackOfIntegers.cpp

#include <iostream>
#include "StackOfIntegers.h"
using namespace std;

int main()
{
  StackOfIntegers stack;

  for (int i = 0; i < 10; i++)
    stack.push(i);

  while (!stack.empty())
    cout << stack.pop() << " ";

  return 0;
}

第06节:vector 类

在这里插入图片描述在这里插入图片描述

第07节:更多编码规范

在这里插入图片描述在这里插入图片描述
73号:一般将关键字放在行首
在这里插入图片描述
74:一般大括号在后面而不是另起一行
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/dldldl1994/article/details/86757485
今日推荐