动态内存和类
1.静态数据成员在类声明中声明,在包含类方法的文件中初始化。初始化时使用作用域运算符来指出静态成员所属的类。但是如果静态成员是整型或者是枚举型const,则可以在类声明中初始化。
.2.C++会自动提供这些函数,如果类中没有定义这些函数的时候。
默认构造函数
默认析构函数
复制构造函数
赋值运算符
地址运算符
3.复制构造函数:用于将一个对象复制到新创建的对象中
何时调用复制构造函数:(1)新建对象并将其初始化为同类现有对象时,复制构造函数将被调用。(2)每当程序生成了对象副本时,编译器都将使用复制构造函数。(注意一点,初始化=定义+赋值,而先定义再赋值不会调用赋值构造函数)
4.默认复制构造函数提供的是浅拷贝,个人理解是不创建新的空间,直接将已存在空间的地址复制给新的对象,这样旧的对象和新的对象都指向同一个内存。
5.静态成员变量为这种类的所以对象共有。
6.如果类中包含这样的静态数据成员,即其值将在新对象被创建时发生变化,则应该提供一个对计数进行更新的显示复制构造函数。
7.不应该将同一个内存释放两次,这样就会造成不确定的危险。
8.如果类中包含了使用new初始化的指针成员,应当定义一个复制构造函数,以复制指向的数据,而不是指针,这种复制被称为深度复制。
9.赋值运算符也存在相同的浅拷贝问题,同理应该使用深拷贝去克服它。注意一点是,需要先判断是都是自己赋值给自己,如果是的话直接返回*this,如果不是则先删除以前在内存中存在的数据。如果不删除,在创建新的内存的时候,指向以前内存的指针就不存在了,就会造成内存泄漏的问题。如果返回的是对象的引用则可以连续操作。
10.当const在函数名前面的时候修饰的是函数返回值。
当const在函数名后面表示是常成员函数,该函数不能修改对象内的任何成员,只能发生读操作,不能发生写操作。该类的this指针为const类型,不能改变类的成员变量的值。
11.静态成员函数在函数原型前面加static。注意:不能使用对象调用静态成员函数,如果静态成员函数是在共有部分声明的话,则可以使用类名和作用域解析运算符来调用它。静态成员函数只能调用静态成员变量。
有关返回对象的说明
1.返回指向const对象的引用
返回对象将调用复制构造函数,而返回引用不会
引用指向的对象应该在调用函数执行时存在
v1与v2被声明为const引用,因此返回必须为const
2.返回非const对象的引用:常用于重载赋值运算符以及重载与cout一起使用的<<运算符。
对于cout与<<一起使用的重载版本来说,必须返回ostream的引用,因为载cout对象中并没有公有的复制构造运算符。
3.返回对象
如果返回的对象是被调用函数中的局部变量,则不应按引用方式返回,因为在函数执行完之后,局部对象将调用析构函数,删除对象。返回引用就没办法指向正确的内存。
4.返回const对象
返回对象是可做为左值的,所有可能会犯 将返回值做为左值的情况。如果返回const对象,就可以避免这种错误。
调用析构函数的三种情况
1.如果对象是动态变量,则当执行完定义该对象的程序块时,将调用该对象的析构函数。
2.如果对象是静态变量,则在程序结束时调用对象的析构函数。
3.如果对象是用new创建的,则需要显示使用delete删除对象时,其析构函数才会被调用。
定位new运算符和new运算符在删除对象时的差别
存在两个问题;
1.在创建第二个对象的时候,定位new运算符使用一个新对象来覆盖第一个对象的内存单元,所有需要提供两个位于缓冲区的不同地址。
2.在用delete[]删除定位new运算符创建的对象时不会自动调用析构函数。因此需要用对象显示的调用析构函数。
注意:删除顺序,是先创建的后删除进行删除,因为晚创建的可能依赖于早早创建的对象。另外仅当所有对象都被销毁后,才能释放用于存储这些对象的缓冲区。