class和struct很大一个区别在于,c除了成员的访问控制权限,struct中的成员默认是public,而class中的field默认是private;class还有一个special的地方是它有构造函数:constructor。
构造函数是class中的一员,和成员变量、其他成员函数一起构成一个完整的class。
构造函数用来在memory中开辟一个内存空间,并返回一个类实例的引用。构造函数包括:初始化构造函数、拷贝构造函数、赋值构造函数。
初始化构造函数顾名思义就是用来创建一个类实例,并对它的成员进行初始化的。下面是个栗子:
class Data
{
private:
int year;
int month;
int day;
bool isAfternoon;
public:
Data(int,int,int);
Data(const Data &data);
~Data(void);
Print(void);
};
Data::Data(int x, int y, int z)
{
year = x;
month = y;
day = z;
}
上面的Data(int,int,int)就是一个初始化构造函数,使用的时候可以这样:
Data today(2016,4,28);
这样我们就通过初始化构造函数创建了一个叫做today的Data对象,并对它的成员变量year、month、day进行了初始化。
接着我们来看拷贝构造函数。什么是拷贝构造函数?推断没错的话应该是去年4月底瑶哥电面的时候问过我的一个问题。拷贝构造函数目的也是创建一个新对象,开辟属于它的内存空间,返回它的一个reference。和初始化构造函数不同,它需要一个已经存在的实例来进行这个创建过程。继续上面的例子,假设有了上面创建的today,现在创建对象night:
Data night(today);
也可以这样:
Data night = today;
需要说的是,拷贝构造函数的拷贝是一种浅拷贝,这意味着上面创建的night和today引用的是同一块内存空间,如果对night中的成员变量进行了修改,那么也会同步到today。
然后是赋值构造函数。从使用上赋值构造函数应该是最简单的。但是从实现角度,因为它要用到运算符的重载就不简单廖。上面的Data的赋值构造函数的声明可以like this:
Data & operate = (const Data &data);
如果这个时候有一个tomorrow对象,用today对它进行赋值,那么将会调用赋值构造函数:
Data tomorrow(2016,4,29);
tomorrow = today;
如果出现=,例如上面的tomorrow = night,调的是赋值构造函数还是拷贝构造函数?如果在进行=之前tomorrow已经创建完成了,比如上面的实现,这个时候就是调用的赋值构造函数。如果一边进行=,一边进行创建,就像Data tomorrow = night,那么就是调用的拷贝构造函数,为了增强代码的可读性,最好这么写:Data tomorrow(night);
最后来一道很常见的考察构造函数的笔试题:“实现一个String类,至少要能实现以下:构造函数,析构函数,拷贝构造函数,重载赋值操作符。”
来一个参考:
class String
{
private:
char *mContent;//记录字符的内容
public:
String(const char *content);
~String();
String(const String &string);
String& operate = (const String &string);
};
String::String(const char *content)
{
if(content==NULL){
this->mContent = new char[1];
this->mContent = '\0';
return;
}
int lenght = strlen(content);
this->mContent = new char[lenght+1];
strcpy(this->mContent, string);
}
String::String(const String &string)
{
int length = strlen(string.mContent);
this->mContent = new char[length+1];
strcpy(this->mContent, string.mContent);
}
String::String& operate = (const String &string)
{
if(string.mContent==NULL)this->mContent=String(string);
strcpy(this->mContent, string.mContent);
}
String::~String()
{
delete this->mContent;
}