通常情况一下,我们会认为一个类中如果不写任何的构造器,析构器,拷贝构造器,赋值运算符重载函数。我们认为他是空。写与不写如下如的结果是类同的。
如例:
class A
{
public:
A(){}
A(const A&){}
A& operator=(const A&){ return *this;}
~A(){}
};
但是当我们一个类中含有对像成员,能否我们认为还是空呢,默认的是不是跟空是等同的呢。
测试构造器的代码:
class A
{
public:
A(){cout<<"A constructor"<<endl;}
A(const A&){cout<<"A copy constructor"<<endl;}
A& operator=(const A&){ cout<<"A operator="<<endl;return *this;}
~A(){cout<<"A destructor"<<endl;}
};
class B
{
public:
B(){cout<<"B constructor"<<endl;}
public:
A a;
};
int main()
{
B b;
return 0;
}
运行结果如下:
A constructor
B constructor
B destructor
A destructor
此时调用的默认无参构造器,如果A的构造器参数是非空的。则调用会出错。
示例如下:
class A
{
public:
A(int){cout<<"A constructor"<<endl;}
A(const A&){cout<<"A copy constructor"<<endl;}
A& operator=(const A&){ cout<<"A operator="<<endl;return *this;}
~A(){cout<<"A destructor"<<endl;}
};
class B
{
public:
B(){cout<<"B constructor"<<endl;}
public:
A a;
};
int main()
{
B b;
return 0;
}
运行结果如下:
g++ -O0 -g3 -Wall -c -fmessage-length=0 -o src\test.o ..\src\test.cpp
..\src\test.cpp: In constructor 'B::B()':
..\src\test.cpp:15:5: error: no matching function for call to 'A::A()'
..\src\test.cpp:15:5: note: candidates are:
..\src\test.cpp:8:2: note: A::A(const A&)
..\src\test.cpp:8:2: note: candidate expects 1 argument, 0 provided
..\src\test.cpp:7:2: note: A::A(int)
..\src\test.cpp:7:2: note: candidate expects 1 argument, 0 provided
..\src\test.cpp: In copy constructor 'B::B(const B&)':
..\src\test.cpp:16:13: error: no matching function for call to 'A::A()'
..\src\test.cpp:16:13: note: candidates are:
..\src\test.cpp:8:2: note: A::A(const A&)
..\src\test.cpp:8:2: note: candidate expects 1 argument, 0 provided
..\src\test.cpp:7:2: note: A::A(int)
..\src\test.cpp:7:2: note: candidate expects 1 argument, 0 provided
Build error occurred, build is stopped
如保来改正的,如果显示的写含有参数的构造器,内容不再是空,包含对成员对象的初始化。
示例如下:
class A
{
public:
A(int){cout<<"A constructor with int"<<endl;}
A(const A&){cout<<"A copy constructor"<<endl;}
A& operator=(const A&){ cout<<"A operator="<<endl;return *this;}
~A(){cout<<"A destructor"<<endl;}
};
class B
{
public:
B():a(1){cout<<"B constructor"<<endl;}
public:
A a;
};
int main()
{
B b;
return 0;
}
《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《
测试拷贝构造函数
class A
{
public:
A(int){cout<<"A constructor with int"<<endl;}
A(const A&){cout<<"A copy constructor"<<endl;}
A& operator=(const A&){ cout<<"A operator="<<endl;return *this;}
~A(){cout<<"A destructor"<<endl;}
};
class B
{
public:
B():a(1){cout<<"B constructor"<<endl;}
B(const B& b){cout<<"B copy constructor"<<endl;}
public:
A a;
};
int main()
{
B b;
return 0;
}
编译结果
g++ -O0 -g3 -Wall -c -fmessage-length=0 -o src\test.o ..\src\test.cpp
..\src\test.cpp: In copy constructor 'B::B(const B&)':
..\src\test.cpp:16:15: error: no matching function for call to 'A::A()'
..\src\test.cpp:16:15: note: candidates are:
..\src\test.cpp:8:2: note: A::A(const A&)
..\src\test.cpp:8:2: note: candidate expects 1 argument, 0 provided
..\src\test.cpp:7:2: note: A::A(int)
..\src\test.cpp:7:2: note: candidate expects 1 argument, 0 provided
Build error occurred, build is stopped
改正如下:
class A
{
public:
A(int){cout<<"A constructor with int"<<endl;}
A(const A&){cout<<"A copy constructor"<<endl;}
A& operator=(const A&){ cout<<"A operator="<<endl;return *this;}
~A(){cout<<"A destructor"<<endl;}
};
class B
{
public:
B():a(1){cout<<"B constructor"<<endl;}
B(const B& b):a(b.a){cout<<"B copy constructor"<<endl;}
public:
A a;
};
int main()
{
B b;
return 0;
}
《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《
同理赋值运算符重载正确如下:
class A
{
public:
A(int){cout<<"A constructor with int"<<endl;}
A(const A&){cout<<"A copy constructor"<<endl;}
A& operator=(const A&){ cout<<"A operator="<<endl;return *this;}
~A(){cout<<"A destructor"<<endl;}
};
class B
{
public:
B():a(1){cout<<"B constructor"<<endl;}
B(const B& b):a(b.a){cout<<"B copy constructor"<<endl;}
B& operator=(const B&b){ a = b.a;cout<<"B operBtor="<<endl;return *this;}
// ~B(){cout<<"B destructor"<<endl;}
public:
A a;
};
int main()
{
B b;
return 0;
}
综上,含有类成员对象的类构造器,拷贝构造器,赋值运算符重载函数。如果采用默认,应用时调用关系是正确的,但是缺陷是浅拷贝(shallow copy )。所以如果需要重写,不能单纯认为是空。要显示的调用成员对象的的类构造器,拷贝构造器,赋值运算符重载函数。不然用空的函数覆盖了默认,后果不堪设想。
如下:
class A
{
public:
A(){cout<<"A constructor "<<endl;}
A(const A&){cout<<"A copy constructor"<<endl;}
A& operator=(const A&){ cout<<"A operator="<<endl;return *this;}
~A(){cout<<"A destructor"<<endl;}
};
class B
{
public:
B():a(){cout<<"B constructor"<<endl;}
B(const B& b){cout<<"B copy constructor"<<endl;}
// B(const B& b):a(b.a){cout<<"B copy constructor"<<endl;}
B& operator=(const B&b){ a = b.a;cout<<"B operBtor="<<endl;return *this;}
~B(){cout<<"B destructor"<<endl;}
public:
A a;
};
void func(B b)
{
}
int main()
{
B b;
cout<<"------------"<<endl;
func(b);
cout<<"------------"<<endl;
return 0;
}
运行结果
A constructor
B constructor
------------
A constructor //认真看,错误就在这里,这样跟本没有完成拷贝,而是默认构造了。
B copy constructor
B destructor
A destructor
------------
B destructor
A destructor
正确:
class A
{
public:
A(){cout<<"A constructor "<<endl;}
A(const A&){cout<<"A copy constructor"<<endl;}
A& operator=(const A&){ cout<<"A operator="<<endl;return *this;}
~A(){cout<<"A destructor"<<endl;}
};
class B
{
public:
B():a(){cout<<"B constructor"<<endl;}
// B(const B& b){cout<<"B copy constructor"<<endl;}
B(const B& b):a(b.a){cout<<"B copy constructor"<<endl;}
B& operator=(const B&b){ a = b.a;cout<<"B operBtor="<<endl;return *this;}
~B(){cout<<"B destructor"<<endl;}
public:
A a;
};
void func(B b)
{
}
int main()
{
B b;
cout<<"------------"<<endl;
func(b);
cout<<"------------"<<endl;
return 0;
}
正确的运行结果:
A constructor
B constructor
------------
A copy constructor //这才是正确的结果
B copy constructor
B destructor
A destructor
------------
B destructor
A destructor