构造函数
派生类不能继承基类的构造函数和析构函数在设计派生类的构造函数时,
不仅要考虑派生类新增数据成员的初始化,也要考虑基类数据成员的初始化
格式
派生类名(参数表) : 基类名1(参数表1), …, 基类名n(参数表n)
{
派生类新增成员的初始化
}
注意事项
4.如果派生类的基类也是一个派生类,则每个派生类只需负责其直接基类的构造,依次上溯。示例如下
5.派生类构造函数负责调用基类构造函数,并为其提供所需的参数,以保证基类初始化时能够获得必要的数据。如果基类的构造函数定义了一个或多个无默认值的参数时,派生类必须定义构造函数。
示例
class A //基类
{
public:
A(int x):a(x){}
private:
int a;
};
class B:public A //派生类
{
public:
B(int x):A(x){} //必须定义构造函数初始化基类数据成员
};
int main()
{
B obj(1);
return 0;
}
拷贝构造函数
格式
类名::类名(const 类名 &源对象) // 对象作为参数
{
…… // 复制被被赋值对象
}
示例1
CPerson(const CPerson &oCPerson) //拷贝构造函数
{
m_lpszName = new char[strlen( oCPerson.m_lpszName )+1];
strcpy(m_lpszName, oCPerson.m_lpszName);
m_lpszSex = new char[strlen( oCPerson.m_lpszSex )+1];
strcpy(m_lpszSex, oCPerson.m_lpszSex);
}
示例 2
#include <iostream> // 编译预处理命令
using namespace std; // 使用命名空间std
class String
{
private:
// 数据成员
char *strValue; // 串值
public:
// 公有成员
String(char *s = "") // 构造函数
{
if (s == NULL) s = ""; // 将空指针转化为空串
strValue = new char[strlen(s) + 1];// 分配存储空间
strcpy(strValue, s); // 复制串值
}
String(const String ©) // 复制构造函数
{
strValue = new char[strlen(copy.strValue) + 1];// 分配空间
strcpy(strValue, copy.strValue); // 复制串值
}
String &operator=(const String ©); // 重载赋值运算符
~String() { delete []strValue; } // 析构函数
void Show() const { cout << strValue << endl; } // 显示串
};
String &String::operator=(const String ©) // 重载赋值运算符
{
if (this != ©)
{ // 目的对象与源对象不是同一个对象
delete [ ]strValue; // 释放存储空间
strValue = new char[strlen(copy.strValue) + 1];// 分配空间
strcpy(strValue, copy.strValue);// 复制串值
}
return *this; // 返回目的对象
}
int main() // 主函数main()
{
String s1("try"), s2, s3(s1); // 定义对象
s2 = s1; // 使用重载赋值运算符
s1.Show(); // 显示串s1
s2.Show(); // 显示串s2
s3.Show(); // 显示串s3
system("PAUSE"); // 输出系统提示信息
return 0; // 返回值0, 返回操作系统
}
析构函数
当派生类对象消亡时,系统会自动调用派生类的析构函数,做一些必要的清理工作在继承过程中,派生类不能继承基类的析构函数,所以派生类需要自己定义析构函数在执行派生类的析构函数时,
基类的析构函数将被自动调用析构派生类对象的步骤顺序是:先调用派生类的析构函数析构派生类对象新增部分,
如果该派生类含有子对象,接下来就析构子对象部分,
最后调用基类的析构函数析构基类部分,派生类的析构顺序恰好与构造顺序相反