类的构造和析构主要内容
类的构造函数
类的析构函数
类的复制构造函数
class Account
{
};
void deposit(double amount);
void withdraw(double amount);
void display();
char* id;
char* pwd;
double balance;
public:
private:
double min_balance;
回顾例:实现转帐,从帐户 A1790153向帐户
A2190156转帐 30000元。
Account a1,a2;
#include,Account.h”
a1.withdraw(30000);
a2.deposit(30000);
a1.display();
a2.display();
a1.display();
a2.display();
void main()
{
}
分析原因
由于对象 a1和 a2在定义时,并没有专门的语句为帐户的余额 balance进行初始化,
因此程序运行时,balance中存放的内容是不确定的
因此,类中应该有一类操作专门负责对象的初始化,使得对象的使用更安全、
可靠
对象的初始化由类的构造函数完成
构造函数的功能是在定义对象时被编译系统自动调用来 创建 对象并 初始化 对象。
其定义格式如下:
构造函数
<类名 >::<类名 >(<参数表 >)
{
<函数体 >
}
对象的初始化例:新开一个户,令卡上初始金额为最小余额。
Account::Account(char* aid,char* apwd,double bal)
{ id = new char[strlen(aid)+1];
pwd = new char[strlen(apwd)+1];
strcpy(id,aid);
strcpy(pwd,apwd);
min_balance = 10;
balance = bal;
}
例:新开一个帐户
Account::Account()
{ id = new char[9];
pwd = new char[7];
strcpy(id,“A0000000”);
strcpy(pwd,“111111”);
balance = 10;
min_balance = 10;
}
仔细观察两个完成初始化功能的函数 ……
构造函数是成员函数,函数体可写在类体内,也可写在类体外。
构造函数的 函数名与类名相同,且 不指定返回值类型,
它有隐含的返回值,该值由编译系统内部使用。
构造函数 可以没有参数,也可以有参数,因此 可以重载,即可以定义参数不同的多个构造函数。
每个类都 必须有一个 构造函数。如果类中没有显式定义构造函数,则编译系统自动生成一个 缺省 形式的 构造函数,作为该类的公有成员。
程序中不能直接调用构造函数,在定义对象时编译系统自动调用构造函数。
构造函数的特点练习,定义一个职员类 Employee的构造函数
(假设有职员编号、姓名、年龄、地址等数据 )
Employee::Employee()
{
}
id = new char[10];
name = new char[20];
age = 0;
address = new char[100];
Employee::Employee(char* pid,char* pname)
{
}
id = new char[strlen(pid)+1];
name = new char[strlen(pname)+1];
age = 0;
address = new char[100];
strcpy(id,pid);
strcpy(name,pname);
编译系统调用构造函数
void main()
{
}
Employee e1;
Employee e2(“00000010”,“Smile”);……
……
思考:当对象生存周期即将完结时,堆对象怎么回收?
析构函数的功能是在对象的生存期即将结束的时刻,由编译系统自动调用来完成一些清理工作。它的调用完成之后,对象也就消失了,相应的内存空间也被释放。
析构函数也是类的一个公有成员函数,它的名称是由类名前面加,~”构成,也不指定返回值类型。和构造函数不同的是,析构函数不能有参数,因此不能重载。
析构函数析构函数定义格式
<类名 >::~ <类名 >()
{
}
<函数体 >
例,Employee::~Employee(){
}
delete id[];
delete name[];
析构函数是成员函数,函数体可写在类体内,也可以写在类体外。
析构函数的 函数名与类名相同,并在前面加,~”字符,
用来与构造函数加以区别。析构函数 不指定返回值类型 。
析构函数 没有参数,因此 不能重载 。一个类中只能定义一个析构函数。
每个类都 必须有一个 析构函数。如果类中没有显式定义析构函数,则编译系统自动生成一个 缺省 形式的析构函数,作为该类的公有成员。
析构函数在对象生存期结束前由编译系统自动调用。
析构函数的特点
constructor vs,destructor
constructor destructor
调用顺序 与创建对象顺序相同 与创建对象顺序相反是否必须 必须 可以没有可否重载 可以 不可以对象的管理 完成对象创建和初始化 不负责对象回收调用者 编译系统 编译系统判断:
1)类必须有构造函数;
2)类必须提供至少一个构造函数;
3)类必须有析构函数;
4)析构函数负责回收该类对象的内存。
复制构造函数
--用一个已知的对象初始化一个同类的对象定义格式:
class <类名 >
{
}
……
……
<类名 > (<参数表 >)
<类名 > (const <类名 >& <对象名 >)
<类名 >::<类名 > (const <类名 >& <对象名 >)
{
<函数体 >
} const可以省略!
思考:类必须有复制构造函数吗?
--如果没有显式定义复制构造函数,编译系统会自动生成一个复制构造函数,其格式为:
<类名 >::<类名 > (const <类名 >& <对象名 >) {}
例 3-11:
复制构造函数与类同名,也不指定返回值类型
复制构造函数只有一个参数,并且是对同类对象的引用复制构造函数只有一个参数,并且是对同类对象的引用
每个类都必须有一个复制构造函数
发生以下三种情况复制构造函数被调用。
--用类的对象去初始化该类的另一个对象时。
--对象作为函数的实参传递给函数的形参时。
--函数返回值是类的对象,函数调用返回时。
例,class Account{
……
Account(char* aid,char* apwd,double bal);
public:
Account(const Account& p);
}
……
Account::Account(const Account& p)
{
}
id = p.id;
pwd = p.pwd;
delete[] name;
delete[] id;
二者顺序不能调换!
浅复制与深复制
--当一个类对象占用了资源时,必须对该类显式定义复制构造函数,保证资源的正常分配。
浅复制
id
pwd
balance
min-balance
id
pwd
balance
min-balance
堆
s1
s2
深复制
id
pwd
balance
min-balance
id
pwd
balance
min-balance
堆堆
s1
s2
类的构造函数
类的析构函数
类的复制构造函数
class Account
{
};
void deposit(double amount);
void withdraw(double amount);
void display();
char* id;
char* pwd;
double balance;
public:
private:
double min_balance;
回顾例:实现转帐,从帐户 A1790153向帐户
A2190156转帐 30000元。
Account a1,a2;
#include,Account.h”
a1.withdraw(30000);
a2.deposit(30000);
a1.display();
a2.display();
a1.display();
a2.display();
void main()
{
}
分析原因
由于对象 a1和 a2在定义时,并没有专门的语句为帐户的余额 balance进行初始化,
因此程序运行时,balance中存放的内容是不确定的
因此,类中应该有一类操作专门负责对象的初始化,使得对象的使用更安全、
可靠
对象的初始化由类的构造函数完成
构造函数的功能是在定义对象时被编译系统自动调用来 创建 对象并 初始化 对象。
其定义格式如下:
构造函数
<类名 >::<类名 >(<参数表 >)
{
<函数体 >
}
对象的初始化例:新开一个户,令卡上初始金额为最小余额。
Account::Account(char* aid,char* apwd,double bal)
{ id = new char[strlen(aid)+1];
pwd = new char[strlen(apwd)+1];
strcpy(id,aid);
strcpy(pwd,apwd);
min_balance = 10;
balance = bal;
}
例:新开一个帐户
Account::Account()
{ id = new char[9];
pwd = new char[7];
strcpy(id,“A0000000”);
strcpy(pwd,“111111”);
balance = 10;
min_balance = 10;
}
仔细观察两个完成初始化功能的函数 ……
构造函数是成员函数,函数体可写在类体内,也可写在类体外。
构造函数的 函数名与类名相同,且 不指定返回值类型,
它有隐含的返回值,该值由编译系统内部使用。
构造函数 可以没有参数,也可以有参数,因此 可以重载,即可以定义参数不同的多个构造函数。
每个类都 必须有一个 构造函数。如果类中没有显式定义构造函数,则编译系统自动生成一个 缺省 形式的 构造函数,作为该类的公有成员。
程序中不能直接调用构造函数,在定义对象时编译系统自动调用构造函数。
构造函数的特点练习,定义一个职员类 Employee的构造函数
(假设有职员编号、姓名、年龄、地址等数据 )
Employee::Employee()
{
}
id = new char[10];
name = new char[20];
age = 0;
address = new char[100];
Employee::Employee(char* pid,char* pname)
{
}
id = new char[strlen(pid)+1];
name = new char[strlen(pname)+1];
age = 0;
address = new char[100];
strcpy(id,pid);
strcpy(name,pname);
编译系统调用构造函数
void main()
{
}
Employee e1;
Employee e2(“00000010”,“Smile”);……
……
思考:当对象生存周期即将完结时,堆对象怎么回收?
析构函数的功能是在对象的生存期即将结束的时刻,由编译系统自动调用来完成一些清理工作。它的调用完成之后,对象也就消失了,相应的内存空间也被释放。
析构函数也是类的一个公有成员函数,它的名称是由类名前面加,~”构成,也不指定返回值类型。和构造函数不同的是,析构函数不能有参数,因此不能重载。
析构函数析构函数定义格式
<类名 >::~ <类名 >()
{
}
<函数体 >
例,Employee::~Employee(){
}
delete id[];
delete name[];
析构函数是成员函数,函数体可写在类体内,也可以写在类体外。
析构函数的 函数名与类名相同,并在前面加,~”字符,
用来与构造函数加以区别。析构函数 不指定返回值类型 。
析构函数 没有参数,因此 不能重载 。一个类中只能定义一个析构函数。
每个类都 必须有一个 析构函数。如果类中没有显式定义析构函数,则编译系统自动生成一个 缺省 形式的析构函数,作为该类的公有成员。
析构函数在对象生存期结束前由编译系统自动调用。
析构函数的特点
constructor vs,destructor
constructor destructor
调用顺序 与创建对象顺序相同 与创建对象顺序相反是否必须 必须 可以没有可否重载 可以 不可以对象的管理 完成对象创建和初始化 不负责对象回收调用者 编译系统 编译系统判断:
1)类必须有构造函数;
2)类必须提供至少一个构造函数;
3)类必须有析构函数;
4)析构函数负责回收该类对象的内存。
复制构造函数
--用一个已知的对象初始化一个同类的对象定义格式:
class <类名 >
{
}
……
……
<类名 > (<参数表 >)
<类名 > (const <类名 >& <对象名 >)
<类名 >::<类名 > (const <类名 >& <对象名 >)
{
<函数体 >
} const可以省略!
思考:类必须有复制构造函数吗?
--如果没有显式定义复制构造函数,编译系统会自动生成一个复制构造函数,其格式为:
<类名 >::<类名 > (const <类名 >& <对象名 >) {}
例 3-11:
复制构造函数与类同名,也不指定返回值类型
复制构造函数只有一个参数,并且是对同类对象的引用复制构造函数只有一个参数,并且是对同类对象的引用
每个类都必须有一个复制构造函数
发生以下三种情况复制构造函数被调用。
--用类的对象去初始化该类的另一个对象时。
--对象作为函数的实参传递给函数的形参时。
--函数返回值是类的对象,函数调用返回时。
例,class Account{
……
Account(char* aid,char* apwd,double bal);
public:
Account(const Account& p);
}
……
Account::Account(const Account& p)
{
}
id = p.id;
pwd = p.pwd;
delete[] name;
delete[] id;
二者顺序不能调换!
浅复制与深复制
--当一个类对象占用了资源时,必须对该类显式定义复制构造函数,保证资源的正常分配。
浅复制
id
pwd
balance
min-balance
id
pwd
balance
min-balance
堆
s1
s2
深复制
id
pwd
balance
min-balance
id
pwd
balance
min-balance
堆堆
s1
s2