复制构造函数
只有一个参数,即对同类对象的引用
形如
X::X(X&)
X::X(const X &)//能以常量对象作为参数,二者选一
如果没有定义,编译默认生成。默认的复制构造函数完成复制功能。
class Complex{
private:
double real,iamg;
}
Complex c1;//调用缺省无参构造函数
Complex c2(c1);//调用缺省的复制构造函数,将c2初始化和c1一样
起作用的三种情况
1)当用一个对象去初始化同类的两一个对象时
2)若果某函数有一个参数是类A的对象,那么该函数被调用时,类A的复制构造函数将被调用
#include <iostream>
using namespace std;
class A
{
public:
A(){};
A(A &a){
cout<<"Copy constructor called"<<endl;
}
};
void Func(A a1)
{
}
int main()
{
A a2;
Func(a2);
return 0;
}
输出结果
Copy constructor called//形参a1的值并不等于实参a2
3)若果函数的返回值是类A的对象,则函数返回时,A的复制构造函数被调用
为什么要自己写复制构造函数
类型转换构造函数
实现类型的自动转换
只有一个参数,不是复制构造函数
编译系统会自动调用,调用的时候,会建立一个临时对象/临时变量
析构函数(Destructor)
成员函数的一种
名字与类名相同
在前面加”~”
没有参数和返回值
一个雷最多只有一个析构函数
在对象消亡时,自动被调用,在对象消亡前做善后工作,如释放分配的内存空间等
定义类的时候没写析构函数,则编译器生成缺省析构函数。
调用说明
1)对象数组生命期结束时,对象数组的每个元素的析构函数都会被调用
#include <iostream>
using namespace std;
class Ctest
{
public:
~Ctest()
{
cout<<"destructor called"<<endl;
};
};
int main()
{
Ctest a[2];
cout<<"end main"<<endl;
return 0;
}
输出
end main
destructor called
destructor called
2)delete运算导致析构函数被调用
int main()
{
Ctest *pTest;
pTest= new Ctest[3];
delete[] pTest;
}
输出
destructor called
destructor called
destructor called//数组里包含三个对象,析构函数被调用三次
先构造的,后析构
后构造的,先析构
静态成员变量和静态成员函数
静态成员:加入static关键字
普通成员变量每个对象有各自的一份,而静态成员变量一共就一份,为所有对象共享
sizeof 运算不会计算静态成员变量
普通成员函数必须作用于某个对象,静态成员函数并不具体作用于某个对象,因此静态成员不需要通过对象就能访问。
静态成员变量本质上是全局变量,哪怕一个对象都不存在,静态成员变量也存在。
静态成员访问方式
1)类名::成员名
2)对象名.成员名
3)指针->成员名
4)引用.成员名
在静态成员函数中,不能访问非静态成员变量,也不能调用非静态成员函数。
this指针
指向成员函数作用的对象
class A
{
int i;
public:
void hello(){cout<<"hello"<<endl;}
};
int main()
{
A *p=NULL;
P->Hello();
}
看上去是有问题的,p为空指针,并没有指向实际的A对象,那么p如何调用Hello?实际上
void hello(){cout<<"hello"<<endl;}
编译时,会等价于
void hello(A *this){cout<<"hello"<<endl;}
p->Hello 翻译为 Hello(p);//p作为参数,输出Hello
再看下边一段代码
class A
{
int i;
public:
void hello(){cout<<i<<"hello"<<endl;}
};
int main()
{
A *p=NULL;
P->Hello();
}
void hello(){cout<<i<<"hello"<<endl;}
等价为void hello(A *this){cout<<this->i<<"hello"<<endl;}
此时,this为空指针,调用Hello(p)会出错
总结
静态成员函数不作用于任何对象,故不能使用this指针。静态成员函数的真实参数的个数,就是程序中写出的参数个数。
常引用
引用前加const关键字,成为常引用,不能通过常引用,修改其引用的变量
作用
当对象作为函数的参数的时候,生成该参数需要调用复制构造函数,效率比较低。用指针作为参数,会影响代码的美观。此时,可以将对象的引用作为参数。
class Sample{…};
void PrintfObj(Sample &o){…};
对象作为函数的参数也有一定的风险性,若函数中不小心修改了形参o,则实参也跟着变,为了避免这种现象:采用对象的常引用作为参数
void PrintfObj(const Sample &o){…};
这样,函数中就能确保不会出现无意更改o值的语句了