构造函数
构造函数可以重载,但是重载可能会出现一些问题,降低了代码的可读性。
例一:
// 类定义
class C1
{
public:
C1(){}; // 默认构造函数
C1(int n){ // 构造函数
cout<<"Constructer using argument 'int n'"<<endl;
};
C1(char *str){ // 构造函数
cout<<"Constructer using argument 'char *str'"<<endl;
};
} c;
// 重载函数声明
void f(int n);
void f(char *str);
void f(C 1 c );
int main()
{
// 重载函数调用代码
f(10); // 调用f(int n),还是f(C 1 c )?
f("test"); // 调用f(char *str),还是f(C 1 c )?
f(c);
}
在函数调用时应注意,这里调用的分别是f(int n)和f(char *str),因为他们精确匹配重载函数参数。然而代码是给程序员看的,这种写法容易让人产生误解。
例二:
类定义同上,对象定义代码如下
C 1 c 1 = 10; // 容易让人误以为是在调用赋值运算符
C 1 c 2 = "test";
要避免这种情况,就要使用关键字explicit,将类改写为
class C1
{
explicit C1(){}; // 默认构造函数
explicit C1(int n){ // 构造函数
cout<<"Constructer using argument 'int n'"<<endl;
};
explicit C1(char *str){ // 构造函数
cout<<"Constructer using argument 'char *str'"<<endl;
};
};
这样,以上c1、c2的定义代码将通不过编译,需要改写为
C 1 c 1(10); // 函数调用形式
C 1 c 2("test");
拷贝构造函数
1. 默认拷贝构造函数可能存在的问题
功能:
只实现数据成员的按位拷贝。如果有内嵌对象,且内嵌对象拥有构造、拷贝构造函数,则也调用内嵌对象的拷贝构造函数。
问题:
1) 不能实现静态数据成员的管理
2) 不能实现深拷贝(有指针的情况下)
2. 什么时候要使用拷贝构造函数
当准备按值传递对象时,才需要拷贝构造函数,如函数参数、函数返回值
3. 如何防止编译器自动生成按位拷贝构造函数
将拷贝构造函数声明为私有的,可以定义,也可以不定以
class NoCC
{
private:
NoCC(const NoCC&); // 可以定义,也可以不定以
// ……
};
int main()
{
NoCC n1;
NoCC n2(n1); // 调用私有拷贝构造函数,编译器将会报错
}