如果在编写类时没有显示的写出其构造函数,析构函数,以及重载赋值操作符,编译器会在编译代码时,会为该类加上这些。
其形式大致如下:
1 A() 2 { 3 } 4 5 A& operator =(const A& a) 6 { 7 // 这个地方可能有点不当,只是为了表明这是一个浅拷贝 8 memcpy(this, &a, sizeof(A)); 9 return *this;10 }11 12 A(const A& a)13 {14 // 这儿调用了赋值重载函数15 *this = a;16 }17 18 // 注意在析构函数前不会加上virtual关键字19 ~A()20 {21 }
下面给出一些示例,注释部分说明了函数调用的情况:
1 void f() 2 { 3 // A()构造函数被调用 4 A a; 5 // A(const A& a)构造函数被调用 6 A b(a); 7 // A(const A& a)构造函数被调用 8 A c = a; 9 // A& operator = (const A& a)赋值操作符重载函数被调用10 b = c;11 }12 13 // 离开f()函数之前,a,b,c的析构函数被调用,做一些清理工作
“A c = a;”
这句代码实际调用的是拷贝构造函数,而非赋值函数。
因此,我们可以构造出这样的代码。
1 class A 2 { 3 private: 4 int *m_data; 5 std::string ss; 6 public: 7 A() 8 { 9 m_data = NULL;10 }11 A(int n)12 {13 m_data = NULL;14 if (n>0)15 m_data = new int[n];16 }17 A& operator =(const A& a)18 {19 memcpy(this, &a, sizeof(A));20 return *this;21 }22 virtual ~A()23 {24 if (NULL!=m_data)25 {26 delete [] m_data;27 m_data = NULL;28 }29 }30 };31 32 33 int main(int argc, char* argv[])34 {35 // 将整数3赋值给一个对象36 A a = 3; 37 return 0;38 }
将整数3赋值给一个A类型对象a,然而以上代码可以编译通过。 -- 有点不合常理
这是由于“单参数构造函数”被自动型别转换(这是一个隐式转换)。
可以通过explicit关键字,阻止“以赋值语法进行带有转型操作的初始化”。如下所示:
1 class A 2 { 3 private: 4 int *m_data; 5 std::string ss; 6 public: 7 A() 8 { 9 m_data = NULL;10 }11 explicit A(int n)12 {13 m_data = NULL;14 if (n>0)15 m_data = new int[n];16 }17 A& operator =(const A& a)18 {19 memcpy(this, &a, sizeof(A));20 return *this;21 }22 virtual ~A()23 {24 if (NULL!=m_data)25 {26 delete [] m_data;27 m_data = NULL;28 }29 }30 };31 32 33 int main(int argc, char* argv[])34 {35 // A a = 3; // 编译无法通过36 A b(3); // 可以编译通过37 38 return 0;39 }
原文链接: https://www.cnblogs.com/kekec/archive/2010/11/16/1878783.html
欢迎关注
微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍
原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/17423
非原创文章文中已经注明原地址,如有侵权,联系删除
关注公众号【高性能架构探索】,第一时间获取最新文章
转载文章受原作者版权保护。转载请注明原作者出处!