如果在编写类时没有显示的写出其构造函数,析构函数,以及重载赋值操作符,编译器会在编译代码时,会为该类加上这些。
其形式大致如下:
A(){}
A& operator =(const A& a)
{
// 这个地方可能有点不当,只是为了表明这是一个浅拷贝
memcpy(this, &a, sizeof(A));
return *this;
}
A(const A& a)
{
// 这儿调用了赋值重载函数
*this = a;
}
// 注意在析构函数前不会加上virtual关键字
~A(){}
下面给出一些示例,注释部分说明了函数调用的情况:
void f()
{
// A()构造函数被调用
A a;
// A(const A& a)构造函数被调用
A b(a);
// A(const A& a)构造函数被调用
A c = a;
// A& operator = (const A& a)赋值操作符重载函数被调用
b = c;
}
// 离开f()函数之前,a,b,c的析构函数被调用,做一些清理工作
“A c = a;”
这句代码实际调用的是拷贝构造函数,而非赋值函数。
因此,我们可以构造出这样的代码。
class A
{
private:
int *m_data;
std::string ss;
public:
A()
{
m_data = NULL;
}
A(int n)
{
m_data = NULL;
if (n>0)
m_data = new int[n];
}
A& operator =(const A& a)
{
memcpy(this, &a, sizeof(A));
return *this;
}
virtual ~A()
{
if (NULL!=m_data)
{
delete [] m_data;
m_data = NULL;
}
}
};
int main(int argc, char* argv[])
{
// 将整数3赋值给一个对象
A a = 3;
return 0;
}
将整数3赋值给一个A类型对象a,然而以上代码可以编译通过。 -- 有点不合常理
这是由于“单参数构造函数”被自动类型转换(这是一个隐式转换)。
可以通过explicit关键字 ,阻止“以赋值语法进行带有转型操作的初始化”。如下所示:
class A
{
private:
int *m_data;
std::string ss;
public:
A()
{
m_data = NULL;
}
explicit A(int n)
{
m_data = NULL;
if (n>0)
m_data = new int[n];
}
A& operator =(const A& a)
{
memcpy(this, &a, sizeof(A));
return *this;
}
virtual ~A()
{
if (NULL!=m_data)
{
delete [] m_data;
m_data = NULL;
}
}
};
int main(int argc, char* argv[])
{
// A a = 3; // 编译无法通过
A b(3); // 可以编译通过
return 0;
}