C++中使用 new
和 delete
运算符来动态控制内存,析构函数不可缺少,否则会导致很多新的编程问题的出现。有时必须重载赋值运算符,从而保证程序正常运行。
静态类成员的特点:无论创建多少个对象,程序都只创建一个静态类变量副本(类的所有对象共享同一个静态成员)。
不能在类声明中初始化静态成员变量
(声明描述了如何分配内存,但不分配内存)。可以在类声明之外单独使用单独语句来进行初始化
(静态成员变量是单独存储,而不属于对象的组成部分)。
静态成员
是整型
或枚举型const
,则可以在类声明中初始化
。
new来分配内存
时,必须在相应的析构函数
中使用delete来释放内存
。如果使用 new[] (包括中括号)
来分配内存
,则应使用delete[](包括中括号)
来释放内存
。
自动存储对象被删除的顺序与创建顺序相反。
静态成员函数
的声明中必须包含关键字 static
,但如果函数定义是独立
的,则其中不能包含关键字static
。原因有二:
- 不能通过对象调用静态成员函数,甚至不能使用this指针。
- 静态成员函数不与特定的对象相关联,只能使用静态数据成员。
C++提供的隐式成员函数:
-
默认构造函数,如果没有定义构造函数
如果没有提供任何构造函数,C++将创建默认构造函数。
StringBad::StringBad() {} // 隐式默认构造函数
编译器将提供一个不接受任何参数、也不执行如何操作的构造函数(默认的默认构造函数)。
-
默认析构函数,如果没有定义
-
复制构造函数,如果没有定义
-
定义
复制构造函数用于将一个对象复制到新创建的对象中。用于初始化过程中(包括按值传递),而不是常规的赋值过程。类的复制构造函数的原型如下:
Class_name(const Class_name &); //接收一个指向对象的常量引用作为参数
-
何时调用?
每当程序生成对象副本时,编译器都会使用复制构造函数。常见的情况:
- 当函数按值传递对象时
- 当函数返回对象时
- 当编译器生成临时对象时
-
默认的复制构造函数的功能
默认的复制构造函数逐个复制非静态成员(
成员复制,也称为浅拷贝
),复制的是成员的值
。⚠️ 警告:如果类中包含了使用new初始化的指针成员,应当定义一个拷贝构造函数,以复制指向的数据
,而不是指针。这种称为深拷贝
。浅拷贝只拷贝指针值(拷贝指针信息)
-
-
赋值运算符,如果没有定义
-
定义和原型函数
C++允许
类对象赋值
,通过自动为类重载复制运算符
来实现。函数原型如下:Class_name & Class_name::operator=(const Class_name &);
-
赋值运算符的作用
解决默认赋值运算符不合适导致的问题。
-
实现复制运算符(进行深拷贝)的注意点:
- 目标对象可能引用以前分配的数据,所以函数应使用 delete[] 来释放数据。
- 函数应当避免将对象赋值给自身:否则给对象重新赋值时,释放内存操作可能删除对象的内存。
- 函数返回一个指向调用对象的引用。
-
-
地址运算符,如果没有定义
当使用一个对象来初始化另一个对象时,编译器将自动生成复制构造函数(创建对象的一个副本)
。例如:
StringBad(const StringBad &)
使用new初始化对象的指针成员时必须小心。具体做法如下:
- 如果在构造函数中使用
new来初始化指针成员
,则应在析构函数中使用delete
。 - new 和 delete必须相互兼容。
new
对应于delete
,new[]
对应于delete[]
- 如果有多个构造函数,则必须以相同的方式使用 new,要么带括号,要么都不带。
- 定义一个拷贝构造函数,通过深拷贝将一个对象初始化为另一个对象。
当成员函数或独立的函数返回对象时,有3种返回方式
-
指向对象的引用
-
指向对象的const引用
-
const对象
使用对象指针时的注意事项
- 使用常规表示法来声明指向对象的指针。
- 将指针初始化为指向已有的对象。
- 可使用 new 来初始化指针,创建一个新的对象。
- 对类使用 new 将调用相应的类构造函数来初始化新创建的对象。
- 可使用 -> 运算符通过指针访问类方法。
- 可对对象指针应用解除引用运算符来获得对象。
待更新