1.类的初始化
class Data {
public:
int ival;
char *ptr;
}
class Data 是否需要构造函数初始化?
不一定需要,可以使用显示初始化,因为它的成员都是public类型,在其他地方可以被调用。而private类型只能在类函数和友元中被引用。
int main()
{
Data local1 = {0, 0};
Data local2 = {1024,"Anna Livia Plurabelle"};
//........
}
显示初始化的缺点:
1)只能被应用在所有数据成员都是公有的类的对象上。
2)它要求程序员的显示干涉,增加了意外和错误的可能性。
2.类的构造函数
1)类的构造函数和类同名。
class Account {
public:
Account();//缺省构造函数
//...
private:
char *_name;
unsigned int _acct_nmbr;
double _balance;
};
2)构造函数唯一的语法限制是:它不能指定返回类型,甚至void也不行。以下两种声明都是错误的。
void Account::Account() {...}
Account * Account::Account(const char *pc){...}
3)c++语言对于一个类可以声明多少个构造函数没有限制,只要每个构造函数的参数表是唯一的即可。
4)在类对象首次被使用之前,构造函数将被应用在该对象上。
Account acct("Ethan Stern");
展开为:
Account acct;
acct.Account::Account("Ethan Stern",0.0);
而 Account *pact = new Account("Michael Lieberman",5000);
可以展开为:
Account *pact;
try
{
pact = _new (sizeof(Account));
pact->Account::Account("Michael Lieberman", 5000.0);
}
catch( std::bad_alloc)
{
//操作符 new 失败
//构造函数没有被执行
}
5 )为构造函数指定实参有三种等价形式:
Account acct1("Anna Press");
Account acct2 = Account("Anna Press");
Account acct3 = "Anna Press";
6 )类的初始化方法:
//缺省Account构造函数
inline Account:: Account()
{
_name = 0;
_balance = 0.0;
_acct_nmbr = 0;
}
//成员初始化表
inline Account::Account():_name(0),_balance(0.0),_acct_nmbr(0){}
7)构造函数不能用const或volatile关键字来声明,以下申明是非法的:
class Account{
public:
Account() const; //error
Account() volatile; //error
// ...
};
显然这不意味着const和volatile类对象不能用构造函数来初始化。而是说,被应用到类对象上的适当的构造函数与该对象是const、非const或volatile无关。只有当构造函数执行完毕,类对象已经被初始化的时候,该类对象的常量才被建立起来。一旦析构函数被调用,常量性就消失了。
因此,一个const类对象在“从其构造函数完成到析构函数开始”这段时间内才被认为是const的,对volatile对对象也是一样的。
8)explicit修饰符
考虑如下代码:
//在某个头文件中
extern void print( const Account &acct );
// ...
int main()
{
print("oops"); //该语句用Account::Account("oops",0.0)将“oops"转化成一个Account对象。
// ....
}
缺省情况下,单参数构造函数(或者有多个参数,除了第一个参数外,其它都有缺省实参)被用作转换操作符,隐式调用构造函数。
无意的隐式类转换,如把"oops"转换成一个Account对象,很难跟踪错误源。关键字explicit被引入到标准c++中,以帮助我们抑制这种不受欢迎的编译器辅助行为。
explicit修饰通知编译器不要提供隐式转换:
class Account {
public:
explicit Account(const char *, double = 0.0);
//...
};
explicit只能应用在构造函数上。
3.缺省构造函数
缺省构造函数是指不需要用户指定实参就能够被调用的构造函数,但不意味着它不能接受实参。只意味着构造函数的每个实参都有一个缺省值与之关联。如下:
//每个都是缺省构造函数
Account::Account() {...}
iStack::iStack( int size = 0) { ... }
Complex::Complex(double re=0.0,double im=0.0) {...}
当我们写
int main()
{
Account acct;
// ...
}
编译器首先检查Account 类是否定义了缺省构造函数以下情况之一会发生
1 定义了缺省构造函数它被应用到acct 上
2 定义了缺省构造函数但它不是公有的acct 的定义被标记为编译时刻错误main()
没有访问权限
3 没有定义缺省构造函数但是定义了一个或者多个要求实参的构造函数acct 的定义
被标记为编译时刻错误实参太少
4 没有定义缺省构造函数也没有定义其他构造函数该定义是合法的acct 没有被初
始化没有调用任何构造函数
4.析构函数
析构函数的名字是在类名前加上波浪线(~),它不返回任何值也没有任何参数。因为它不能指定任何参数,所以它也不能被重载。例子:
class Account {
public:
Account();
explicit Account(const char *, double=0.0);
Account( const Account &);
~Account();
//...
private:
char *_name;
unsigned int _acct_nmbr;
double _balance;
};
inline Account::~Account()
{
delete [] _name;
return _acct_nmbr(_acct_nmbr);
//以下数据成员没有必要reset
_name = 0; //没有必要
_balance = 0.0; //没有必要
_acct_nmbr = 0; //没有必要
}
析构函数不局限在放弃资源上。一般地,析构函数可以执行“类设计者希望最后一次使用对象之后执行的任何操作”。
构造函数和析构函数个数:
#include "Account.h"
Account global("James Joyce"); ///1个构造函数
int main()
{
Account local("Anna Livia Plurabelle", 10000); ///1个构造函数
Account &loc_ref = global; 类对象的引用声明,不调用构造函数,引用被用作一个已被构造的对象的别名。
Account *pact = 0;类对象的指针声明,不调用构造函数 ,指针只是指向一个被构造的对象的别名。
Account local_too("Stephen Hero"); ///1个构造函数
pact = new Account("Stephen Dedalus"); ///1个构造函数
delete pact;
}