1、编译器会为类生成默认的构造函数、复制构造函数、赋值函数、析构函数,当然默认的这些函数,只是简单的将对象的成员进行赋值。
2、如果类中的成员对象包含有需要通过new动态分配内存的成员,则需要重新定义复制构造函数、重载赋值操作符、析构函数、带参数的构造函数,默认的构造函数。
3、派生类构造时,会先调用基类的构造函数(根据派生类的构造函数类型,调用基类对应形式的构造函数),接着调用派生类型的构造函数。
4、当类的生命周期结束时,会先调用派生类的析构函数、接着调用基类的析构函数。
5、构造函数和析构函数不能被继承,各自处理各自成员赋值与析构。
6、深入理解对象生命的开始、结束,以及对象在内存中的位置(是在栈上、堆上?)、对象成员的内存布局,是理解上面四点的关键,防止内存泄漏的关键。
下面的代码对以上6点进行实验,细细琢磨.基类文件people.h、people.cpp,派生类文件woman.h、woman.cpp,主函数文件testmain.cpp
#ifndef PEOPLE_H
#define PEOPLE_H
class people
{
private:
char *name;
public:
people(); //默认的构造函数
people(const char *s); //带参数的构造函数
people(const people& p);//复制构造函数
people & operator=(const people& p); //赋值函数
~people();
};
#endif
#include "people.h"
#include <stdio.h>
#include <string.h>
people::people() //默认的构造函数
{
printf("调用了默认的构造函数people()\n");
name = new char[strlen("hello")+1]; //分配在堆上
strcpy(name,"hello");
}
people::people(const char *s) //带参数的构造函数
{
printf("调用了有参构造函数people(const char* s)\n");
name = new char[strlen(s)+1];
strcpy(name,s);
}
people::people(const people & p)
{
printf("调用了复制构造函数people(const people &p\n");
name = new char[strlen(p.name)+1];
strcpy(name,p.name);
}
people & people::operator=(const people &p)
{
printf("调用了赋值函数operator=\n");
if(this == &p)
return *this;
else
{
delete name;
name = new char[strlen(p.name)+1];
strcpy(name,p.name);
return *this;
}
}
people::~people()
{
printf("析构函数被调用~people()\n");
delete name;
}
#ifndef WOMAN_H
#define WOMAN_H
#include "people.h"
class woman : public people
{
private:
char *company; //增加一个指针成员,new分配内存,重新修改构造函数和析构函数
int age;
public:
woman();//默认构造函数
woman(const char * c,int a,const char * s); //有参数构造函数
woman(const woman & w); //复制构造函数
woman & operator=(const woman &w); //重载赋值操作符
~woman();
};
#endif
#include "woman.h"
#include <stdio.h>
#include <string.h>
woman::woman()
{
printf("调用了默认的构造函数woman()\n");
char *s = "world";
company = new char[strlen(s)+1];
strcpy(company,s);
age = 99;
}
woman::woman( const char * c,int a,const char * s):people(s)
{
printf("调用了有参数的构造函数woman( const char * s,int a)\n");
company = new char[strlen(c)+1];
strcpy(company,c);
age = a;
}
woman::woman(const woman &w):people(w) //派生类的复制构造函数定义,由于派生类只能访问自己的私有成员,因此需调用基类的复制构造函数people(const people & p)
{ //注意基类的复制构造函数的参数类型为people,而这里传递的是派生类类型woman,基类会使用派生类型中的基类部分来构造基类对象
printf("调用了复制构造函数woman(const woman &w)\n");
company = new char[strlen(w.company)+1];
strcpy(company,w.company);
age = w.age;
}
woman & woman::operator=(const woman & w) //这不是构造函数,因此不能够通过直接调用基类的构造函数来实现派生类对象中基类成员赋值
{
printf("调用了赋值函数woman::operator=(const woman & w)\n");
if (this == &w)
return *this; //自己给自己赋值
else
{
delete company; //删除原来占用的内存空间
people::operator=(w); //调用基类的赋值操作,完成派生类对象中的基类对象的赋值,方式比较奇怪,先记住
company = new char[strlen(w.company)+1];
strcpy(company,w.company);
return *this;
}
}
woman::~woman()
{
printf("调用了析构函数~woman()\n");
delete company;
}