构造函数
● 构造函数的主要功能是: 为对象分配空间,也可用来为类数据成员赋初值。 该函数没有返回类型,不能有return语句;甚至 void也不行。
● 在实际应用中,一般都要给类声明和定义构造函数,如果没有声明和定义,编译系统就自动生成一个默认的构造函数,这个默认的构造函数不带任何参数,只能给对象开辟一个存储空间, 而不能为对象中的数据成员赋初值, 此时数据成员的值是随机的。
如果在类中显式声明了构造函数,无论是否有参数,编译器都不会再为之生成任何形式的构造函数, 如果你还需要不带参数的默认构造函数,可以手动声明一个。
● 默认构造函数是指不需要指定实参就能被调用的构造函数, 这并不意味着它不能接受实参。 只意味着构造函数的每个参数都有一个默认值与之关联。
以下函数都是默认的构造函数
Time() {} 没有参数的构造函数
参数被指定的默认构造函数
Time(int size = 9){}
Time(double re=5.2,double im=0.5){}
注意: 对象所占据的内存空间只是用于存放数据成员, 成员函数不在每一个对象中存储副本。
● 下面看一个数据成员被初始化的程序:
class Time
{
public:
unsigned short hour;
unsigned short minute;
unsigned short second;
const char *ptr;
};
int main()
{
Time myTime = { 100,200,300 ,"huang"}; 用显示初始化列表初始化公有的数据成员
cout << myTime.hour << " " << myTime.minute << " " << myTime.second <<" " << myTime.ptr << endl;
system("pause");
return 0;
}
根据数据成员被声明的顺序,显示初始化列表中的值一一对应初始化。
如果这样初始化就错误:
Time myTime = { "huang",100,200,300 }; 用显示初始化列表初始化公有的数据成员
显示初始化列表有两个缺点: 它只能被应用到所有数据成员都是公有的类的对象上。它要求程序员的显示干涉,增加了意外(忘了提供初始化表) 和 错误(弄错了初始值顺序)的可能性。
在某些应用中,通过显示列表初始化,用常量值初始化大型数据结构比较有效。
限制对象创建
● 构造函数的可访问性由其声明所在的访问区来决定。 可以通过把相关的构造函数放到非公有访问区内, 从而限制或显式禁止某些形式的对象创建。
● 注意: 一般构造函数通常被声明为公有,如果是私有,那么在main函数中创建对象不能为其成员初始化, 因为没有访问权限。
如果说构造函数时私有的,那么该函数就不能被其他类或者全局函数所使用。而创建C++ 实例需要调用构造函数。 如果构造函数私有,除了类自己的方法外,其他类不能构造这个类的实例。所以,在一般情况下,构造函数是私有,其他类使用它就很困难了。
但是, 有时候不希望其他对象能够实例化一个类,就是这个类只需要一个实例的时候, 为了避免其他外部类创建多个实例的时候,通过把构造函数定义为私有的。
拷贝构造函数
● 该函数是一种特殊的构造函数,具有一般构造函数的所有特性,其形参是本类的对象的引用。 其作用是使用一个已经存在的对象去初始化同类的另一个新对象。
● 其形式为:
类名(类名 &对象名)
{
//statement
}
注意: 其中 “&对象名 ” 表示对一个对象的引用, 该参数是一个已经初始化的类对象。该参数(对象的引用)是一个不可变的const类型。拷贝构造函数要调用基类的拷贝构造函数和成员函数。
● 如果没有定义类的拷贝构造函数,系统会在必要时自动生成一个默认的拷贝构造函数,该函数的功能是: 把已存在的对象中数据成员的值都一一对应复制到新建立的对象中。 因此,可以说完成了同类对象的创建, 两个对象中的数据成员的值相同,即完全相同的属性。
调用拷贝构造函数
● 一般来说,以下三种情况拷贝构造函数会被调用:
用类的对象去初始化该类的另一个对象时。
函数的形参是类的对象时,函数调用过程中进行形参和实参的复制时。
函数的返回值是类的对象, 函数执行完进行返回时。
下面看一个示例程序:
class Point
{
public:
Point(int xx = 0,int yy = 0)
{
X = xx;
Y = yy;
cout << "构造函数被调用!" << endl << endl;
}
Point(const Point &p)
{
X = p.X; 为新创建的对象的成员赋初值
Y = p.Y;
cout << "拷贝构造函数被调用!" << endl << endl;
}
int getX() { return X; }
int getY() { return Y; }
private:
int X, Y;
};
void fun(Point pt)
{
cout <<"输出fun 函数中的值"<< pt.getX() << endl << endl;
}
Point myFun()
{
Point pt(1, 5); 调用构造函数
return pt; 函数返回值是类对象,返回函数时,拷贝构造函数被调用
}
int main()
{
第一种情况时
Point A(2, 3); 调用构造函数
Point B(A); 调用拷贝构造函数
cout << B.getX() << endl << endl;
第二种情况时
Point C(5, 6); 调用构造函数
fun(C); 函数的形参为类的对象, 当调用函数时,拷贝构造函数被调用
第三种情况时
Point D;
D = myFun();
cout << "输出对象D的X的值:" << D.getX() << endl << endl;
system("pause");
return 0;
}