马上考试了,好紧张,赶紧学点。。
成员对象和封闭类
一个类的成员变量如果是另一个类的对象,则该成员变量称为“成员对象”。这两个类为包含关系。包含成员对象的类叫封闭类。
执行封闭类的构造函数时,先执行成员对象的构造函数,然后执行本类的构造函数。
当封闭类对象消亡时,先执行封闭类的析构函数,然后在执行成员对象的析构函数,成员对象析构函数的执行次序和构造函数的执行次序相反。
友元
友元函数的目的是访问类的私有成员。
友元类的关系不具有传递性也不具有对称性
this指针
调用一个成员函数时,编译器自动向函数里传入this指针,该指针指向调用该函数的对象的指针。
静态成员是类具有的属性,不是对象的特征,所以静态成员函数不具有this指针
运算符重载
赋值运算符和地址运算符系统提供了默认重载。对于赋值运算符系统默认重载为对象成员变量的复制,对于地址运算符系统默认重载为返回任何类对象的地址。
运算符重载的写法:
void operator = (args){
// dosomething...
}
运算符重载表示为成员函数和友元函数
运算符重载表示为类的成员函数时,对于二元运算符只需要传递一个参数,参数数量总是少一个
运算符重载表示为类的友元函数是,对于二元运算符需要传递两个参数
使用成员函数虽然方便,对于重载+运算符,只能将对象放在左边,例如:
Object operator + (const int &other){
return this->num + other;
}
int res = obj + 1; // access √
int res = 1 + obj; // error ×
所以只能使用友元函数将两个参数都列出来,即可解决问题。
重载赋值运算符
赋值运算符必须重载为成员函数。
因为等号通常连用,所以operator = 函数通常要返回引用。
浅拷贝和深拷贝
对于以下使用复制构造函数时,系统会进行浅拷贝:
Object p1;
Object p2(p1);
Object p3 = p1;
此时如果Object类中有定义指针成员变量,复制构造函数会将指针的值(指针里面存的是地址)原封不动复制过去,这样每个对象里存的地址虽然地址存放的空间是新开辟的空间,但地址所指向的值是同一个地址。这样,当p1的指针成员变量改变时,p2、p3存放的指针变量的值都会跟着改。
浅拷贝的坏处:
当p1消亡时,需要释放构造函数中动态申请的空间,而当对象p2消亡时,也会试图释放这个空间。重复释放同一块空间会产生错误。
看下面一种情况
Object p4;
p1.num = new int(1);
p4 = p1;
语句p4=p1将p1的所有变量都复制给了p4,这时,p4的num也被覆盖了,他是个指针,这个指针所指向的变量永远也找不回来了,则这块内存永远也不会被释放,成为内存垃圾。
所以重载赋值运算符给他深拷贝一下。
class Object{
public:
int *num;
Object(){}
Object(const Object &other){
if(this!=&other){
num = new int();
*num = *other.num;
}
}
Object& operator=(const Object &other){
if(this == &other) return *this;
delete this->num;
this->num = new int(*other.num);
return *this;
}
~Object(){
if(this->num!= nullptr){
delete this->num;
}
}
};