析构函数(destructor):名称与类名相同,且带前缀~的成员函数称为析构函数。
从一个函数(或块)中退出时,编译器将自动销毁在该函数(或块)中创建的对象。但是,对象可能已经聚集了资源(动态内存、磁盘块、网络连接等),这些资源储存在对象的数据成员中,由成员函数操控。由于对象被销毁(退出函数)后不可再用,因此,必须释放该对象储存的资源。
为了帮助对象完成这些工作,在退出函数(或块)时,所有在该函数(或块)中静态创建(即不使用 new()操作符创建)的对象都将调用析构函数。析构函数将释放对象储存的所有资源。换言之,析构函数提供了一种机制,即对象在被销毁前可自行处理掉自身储存的资源。
复制构造函数(copy constructor):这是一个特殊的构造函数,用于通过现有对象创建新对象,因而称为复制构造函数。
当内置数据类型变量(如int和char)从一个函数按值传递至另一个函数时,由编译器负责复制该变量,并将其副本传递给被调函数(called function)。
如果类的实现者不提供复制构造函数,编译器将会自动生成一个复制构造函数,当然其中所有数据都是值传递行为,这在动态内存中是不允许的。
出现下列情况时,将调用复制构造函数:
对象从一个函数按值传递至另一个函数时;
对象从函数按值返回时;
通过现有对象初始化一个新对象时。
赋值操作符赋值操作符(assignment operator):复制构造函数用于通过现有对象创建新对象,而赋值操作符用于将现有对象显式赋值给另一现有对象。赋值是用户显式完成的操作。
与复制构造函数相同,赋值操作符也是值传递行为。
对于任何赋值操作符,都应注意以下几点:
确保对象没有自我赋值(如a = a)。
复用被赋值对象中的资源或销毁它。
从源对象中将待复制内容复制到目的对象。
最后,返回对目的对象的引用。
this指针类的每个成员函数都有一个特殊的指针——this。这个this指针内含调用成员函数的对象的地址(即this指针总是指向目标对象)。this指针只在成员函数内部有效,this是C++中的关键字。
即this指针指向的是对象地址/对象名。
通过a对象调用Push成员函数。在Push成员函数内部,this指针持有a对象的地址。以这样的方式,成员函数可以访问对象内的任何元素(数据成员和成员函数)。如第2章所述,编译器像实现其他函数那样,实现每个成员函数,但是,每个成员函数应该可以通过某种方法访问调用它的对象。为达到这个目的,this指针将作为隐藏的参数传递给每个成员函数,且 this 指针通常是函数接收的第1个参数(其后是已声明的其他参数)。
什么时候必须使用 this 指针?当我们希望返回对调用某函数的对象的引用时,必须使用*this;另一种情况是,我们希望获得对象的地址,也必须显式使用this名称。到目前为止,这是显式使用this名称最常见的两种情况;还有一种情况是防止命名冲突时,还有想将对象本身的指针或者引用给别的函数时。
return this; // 返回对象本身的指针 return *this; // 返回对象本身的引用 void a::fun(int x) { this->x=x+1; //此处如果不使用this,将无法区分x属于谁 } 编译器生成的成员函数当您使用一个对象来初始化另一个对象时,编译器将自动生成上述构造函数(称为复制构造函数,因为它创建对象的一个副本)。
具体地说,C++自动提供了下面这些成员函数:
默认构造函数,如果没有定义构造函数;
默认析构函数,如果没有定义;
复制构造函数,如果没有定义;
赋值运算符,如果没有定义;
地址运算符,如果没有定义。
更准确地说,编译器将生成上述最后三个函数的定义——如果程序使用对象的方式要求这样做。例如,如果您将一个对象赋给另一个对象,编译器将提供赋值运算符的定义。
1. 默认构造函数如果没有提供任何构造函数,C++将创建默认构造函数。
例如,假如定义了一个Klunk类,但没有提供任何构造函数,则编译器将提供下述默认构造函数:
因此为了防止这种现象,必须显示写出默认构造函数,如:
Klunk::Klunk(){ klunk_ct=0; ... }带参数的构造函数也可以是默认构造函数,只要所有参数都有默认值。例如,Klunk类可以包含下述内联构造函数:
Klunk::Klunk(int n=0){ klunk_ct=n; ... }因此不要同时声明两种形式的默认构造函数,否则编译器不知道将参数传给谁,会报错!