class A{
int *m_pi;
public:
A()
{
m_pi = new int;
}
~A()
{
delete m_pi;
}
};
void func(A _a)
{
int a = 0;
}
void main()
{
A a;
func(a);
}
运行后崩溃,原因是当调用func时,产生一个临时对象,并未调用构造函数,调用默认的位拷贝复制构造函数,然后析构掉了 m_pi 的内存,程序结束析构a时崩溃,解决方案是重载拷贝构造函数
class A
{
int *m_pi;
public:
A()
{
m_pi = new int;
}
~A()
{
delete m_pi;
}
A(A &_a)
{
m_pi = new int;
*m_pi = *_a.m_pi;
}
};
void func(A _a)
{
int a = 0;
}
再考虑,在A中加一个CArray对象
class A
{
int *m_pi;
CArray <int,int &> m_arr;
public:
A()
{
m_pi = new int;
}
~A()
{
delete m_pi;
}
};
void func(A _a)
{
int t = 0;
}
主函数:
A a;
func(a);
编译报错:
“CObject::CObject”: 无法访问 private 成员(在“CObject”类中声明)
原因:func传入实参后会生成临时对象,用默认的拷贝构造函数初始化临时对象(因为这里未定义拷贝构造函数),而默认的拷贝构造函数会依次调用A类成员的拷贝构造函数,如果未定义,则会调用默认的,对于CArray来说,虽然未定义了拷贝构造函数,但其基类CObject定义了,但为private权限,编译报错。
private:
CObject(const CObject& objectSrc); // no implementation
void operator=(const CObject& objectSrc); // no implementation
对于赋值操作符,同样的
主函数
A a;
A b;
b = a; // 不同于 A b = a 出现第一种错误,编译器?
报错:
“CObject::operator =”: 无法访问 private 成员(在“CObject”类中声明)
解决方案:
重载操作符
A &operator=(A &)
{
return *this;
}
定义拷贝构造函数
A(A &)
再考虑
class A
{
int m_a;
CArray <int,int> m_arr;
public:
A(int i){};
};
void main()
{
A a;
CArray<A,A &> arr;
arr.Add(a);
}
“A”没有合适的默认构造函数可用
原因:
可能是因为进入CArray的类型必需有不带参数构造函数,我们将带参数构造函数去掉
http://hi.baidu.com/idealsoft/item/4de85dcac49b2c2847d5c07d
arr.Add(a) 时,会调用A的=,而未定义,则逐次调用成员的,包括CArray成员m_arr,因为Add函数的签名要求输入参数的类型为A&,所以当编译器编译语句:arr.Add(a); 时会自动将a强制转换成A的引用,即将这条语句编译成:A& newElement = b; arr.Add(newElement); 赋值操作就这样出现了!解决方案:定义=操作符
A &operator=(A&)
http://blog.csdn.net/vincent_lon/article/details/2950218
此外,若将CArray参数改为传值CArray<A,A> arr;,则报错:
add 的参数变为值传递,需要拷贝构造函数支持,而我们的类没有,CArray同样没有,CObject有,但是私有,所以编译报错,解决方案为定义拷贝构造函数:
A(A &){}
A(){}
别忘了再定义一个无参数构造函数
结论:当你的类有CArray成员时,
1 值类型,为类准备无参数构造函数,拷贝构造函数和=重载函数。
2 引用类型,=操作符,无参数构造函数
ps : 2014.6.18
CArray 继承自 CObject, 而CArray只显式定义了无参数默认构造函数,而没有定义拷贝构造和赋值操作符重载函数,A在未定义相关函数的情况下进行拷贝或赋值操作时,
依次调用类体各成员对象的拷贝和赋值操作符重载函数,对于CArray对象,由于未显式定义拷贝和赋值操作符重载函数,故编译器在自动生成的 copy及”=“函数中,调用基类CObject 的拷贝构造 和 ”=“操作符函数,而这两个函数正被CObject声明为private权限,即使在派生类CArray中亦无法访问。
得出:
在设计一个基类时,
1.禁止该类被直接实例化,则将构造函数申明为 private or protected,当申明为private时,该类及其所有派生类都无法实例化,如:
class A
{
private:
A(){}
};
class B : public A
{
public:
B(){}
};
error C2248: “A::A”: 无法访问 private 成员(在“A”类中声明)
2.如果处于安全考虑,强制要求其派生类在显式定义 复制控制(拷贝构造和赋值操作符函数),则可将 2个复制控制函数申明为private,如果申明为 protected,则只能在类及派生类体内进行对象复制操作。