(一)this指针
下面是一个简单的商品类
#include<iostream>
using namespace std;
#pragma warning (disable:4996)
class CGoods
{
public:
CGoods(char *name, float price, int amount)
{
cout << "CGoods::CGoods(char*,float,int)" << endl;
mname = new char[strlen(name) + 1]();
strcpy(mname, name);
mprice = price;
mamount = amount;
}
~CGoods()
{
cout << "~CGoods()" << endl;
delete[]mname;
mname = NULL;//防止野指针生成
}
void Show()
{
cout << "name:" <<mname << endl;
}
private:
char *mname;
float mprice;
int mamount;
};
int main()
{
CGoods good1("good1", 1000, 20);
//good1 = "good2";
CGoods good2("good2", 2000, 10);
good1.Show();
good2.Show();
return 0;
}
结果:
有一个疑问的,Show()函数原型并没有指出是哪一个对象的名称,为什么调用的时候会打印相应对象的名称。下面是C语言中打印名称。Show函数中的形参会接收good1和good2的地址,从而知道要打印的是哪个商品的名称。而C++中Show函数你并没有任何形参来接收对象的地址。原因是普通成员方法中都有this指针,指向对象的内存。
该例子中this指针类型为CGoods *const this
注意: this指针的指向不能被改变
(二)默认函数
- 构造函数:初始化对象的内存空间
- 对象生成:对象开辟内存,调用构造函数
- 系统提供的默认的构造函数 CGoods( ) { } 用户提供系统就不会在提供
- 不能手动调用(构造函数是类成员方法用于生成对象的,对象不完整不能调用构造函数,不能决定自己的出生)
- 可以重载(生而不同)
- 存在this指针,指向的是对象的内存
- 析构函数:释放对象所占资源
栈上 系统开辟和释放
堆上 用户开辟和释放
- 对象销毁:调用析构函数,释放对象所占内存
- 系统提供的默认的析构函数 ~CGoods( ) { } 用户提供系统就不会在提供
- 可以手动调用但不建议(退化成一个普通的成员方法,系统还会在调用一次析构函数。析构函数中指针不置成NULL,会释放两次程序崩溃。可以决定自己的死亡)
- 不可以重载(死了都一样)
- 存在this指针,指向的是对象的内存
构造与析构的顺序:先构造后析构。由于内存是在栈上开辟,就要遵循栈的规则,所以,多个对象时,先构造的后析构。
- 拷贝构造函数
- 作用:用一个已存在的对象生成一个相同类型的新对象。
- 形参必须用引用,防止形参对象构造递归构造
- 有指针类型,考虑是否实现深拷贝
(1)默认的拷贝构造函数是浅拷贝,程序崩溃。
CGoods(const CGoods& rhs)
{
mname = rhs.mname;
mprice = rhs.mprice;
mamount = rhs.mamount;
}
CGoods good1("good1", 1000, 20);
CGoods good2 =good1;//用一个已存在的对象生成一个相同类型的新对象。
(2)成员变量中有指针就应该实现深拷贝。
//深拷贝版本的拷贝构造函数
CGoods (const CGoods& rhs)
{
mname = new char[strlen(rhs.mname)+ 1]();
strcpy(mname,rhs.mname);
mprice = rhs.mprice;
mamount = rhs.mamount;
}
(3)没有&,调用函数是一个死循环,形参对象无法生成。有&,就不需要调用函数生成形参。
- 赋值运算符重载函数
- 作用:用一个已存在对象,赋值给相同类型的对象。
- 形参const,防止修改实参,接收隐式生成临时对象。
- 设计流程:防止自符值,释放就资源,开辟新资源,赋值。
(1)系统默认给出的赋值运算符重载是浅拷贝,程序崩溃。
//自赋值判断
CGoods & operator =(const CGoods&rhs)
{
if (this == &rhs)
{
return *this;
}
mname = rhs.mname;
mprice = rhs.mprice;
mamount = rhs.mamount;
}
(2)深拷贝
//自赋值判断
CGoods & operator =(const CGoods&rhs)
{
cout << this << " operator =" << endl;
if (this != &rhs)
{
delete []mname;//释放旧内存
mname = new char[strlen(rhs.mname) + 1];开辟空间
strcmp(mname,rhs.mname);//赋值
mprice = rhs.mprice;
mamount = rhs.mamount;
}
return *this;
}
CGoods & operator =(const CGoods&rhs)
(3)引用:使用&效率会高,&支持连续赋值
(4)const:CGoods & operator =(const CGoods&rhs):防止实参被修改,接收隐式生成的临时量(常量),所以要用常引用。
临时量:临时对象和临时变量。内置产生的临时量:常量(存储器);自定义类型产生的临时量:变量(内存)
显示生成临时对象:程序指明要生成的临时对象类型,good3 = CGood("good3")
隐式生成临时对象:编译器推演需要的对象类型,good3 = "good3"变得和引用帝乡一样的生存周期。
生存周期:表达式结束,;?
引用会提升临时对象的生存周期,使临时对象
CGood = char*无法转换,“good3”调用带一个参数的构造函数,生成临时对象,在赋值给rhs对象,当表达式结束临时对象销毁。