关于构造,析构,复制构造,=,和自动创建无名变量
总结:
1.在新定义对象时,=调用复制构造函数,而对已有对象,=是运算符=
2.在计算时,如果类型不符,系统强制类型转换,调用最接近的构造函数,即 无名对象(a) ,在完成此运算符对应的计算后,该无名变量就被析构掉
例1:
#include<iostream> using namespace std; class A{ float x,y; public: A(){ x=0; y =0; cout<<"调用无参构造函数\n";} A(float a){ x=a ; y= 0; cout<<"调用一个参数的构造函数\n"; } A(float a,float b){ x=a; y =b; cout<<"调用两个参数的构造函数\n";} A(A &a){ x= a.x ; y = a.y; cout<<"调用复制构造函数\n";} ~A(){cout<<"调用析构函数\n";} //A & operator = (A & a){ x=a.x; y =a.y; cout<<"调用了运算符=的重载\n";} void Print (){ cout<<x<<'\t'<<y<<endl;} }; void f(){ A a0; //此处若用 A a0 = 2+3; 则会报错 //因为对象定义时, = 采用的是复制构造函数,没有相一致的复制构造函数对应 a0 = 2+3; //定义构造函数时, A a0(2,3); 也可以写成 A a0 = A(2,3); a0.Print(); } A a1(7.0,3.0); //主函数前的对象,先调用两个参数的构造函数 int main(){ f(); // A a0 调用无参构造函数 // 2+3 = 5 一般计算 // 强制类型转换,临时对象(5) 生成临时对象,用数值5对其构造,调用一个参数的构造函数 // 利用"=",a0调用复制构造函数,复制临时对象(5)这个对象 // Print()函数打印 // 第一个析构的是无名对象,第二个析构的是a0,注意无名变量析构时也会调用析构函数 A a2(a1); // 利用构造函数的一般形式,对a2构造,复制对象为a1 // 第三个析构是对a2的析构,第四个析构是对全局对象a1的析构 return 0; }
结果:
调用两个参数的构造函数
调用无参构造函数
调用一个参数的构造函数
调用析构函数
5 0
调用析构函数
调用复制构造函数
调用析构函数
调用析构函数
例2:
#include<iostream> using namespace std; int MMMax=0; class A{ int x,y; static int count; public: A(int a = 0 ,int b = 0){ x = a ; y = b ; MMMax = ++count; cout<<"调用了两个参数的构造函数\n"; } A(A &c){ x=c.x; y=c.y; MMMax = ++count; cout<<"调用了复制构造函数\n"; } ~A(){ count--; cout<<"调用了析构函数\n";} int getnum(){ return count;} }; int A::count = 0; int main(){ A a1,a2(10,20); // a1 两个默认值的构造函数 a2 带有两个参数的构造函数 // count 作为静态变量,调用构造函数时+1,所以这里0+2=2 cout<<"count="<<a2.getnum()<<endl; A a3=a1; // 利用复制构造函数,直接将a1的内容复制给a3,中间没有无名对象过程,复制的过程取决于复制构造函数 // 当对象新定义时,=调用复制构造函数 cout<<"count="<<a3.getnum()<<endl; a1 = A(20,30); // 强制类型转换,用两个参数的构造函数构造无名对象 // a1是已有的对象,所以利用运算符=,将无名对象复制给a1 // 无名对象调用析构函数析构,在结束复制过程后即析构 // 调用析构函数时会用count--,所以MMMax和count的值不一样 cout<<"count="<<a1.getnum()<<endl; cout<<"MMMax="<<MMMax<<endl; A a4=a2; // 当对象新定义时,=调用复制构造函数 a4 = a2; // 当对象是已有时,=调用运算符=的重载 // 析构函数的顺序分别是a4,a3,a2,a1 return 0; }
结果:
调用了两个参数的构造函数
调用了两个参数的构造函数
count=2
调用了复制构造函数
count=3
调用了两个参数的构造函数
调用了析构函数
count=3
MMMax=4
调用了复制构造函数
调用了析构函数
调用了析构函数
调用了析构函数
调用了析构函数
例3:
#include<iostream> using namespace std; char gid = 'A'; class Number{ private: int i; char id; public: Number(int x=0){ i = x; id =gid++; cout<<"Constructor Number:"<<id<<i<<endl; } Number( const Number &x ){ i=x.i; id =gid ++; cout<<"Copy Number:"<<id<<i<<endl; } ~Number(){cout<<"Destructor Number:"<<id<<i<<endl;} Number operator+(const Number &x); }; Number Number::operator+(const Number &x) { Number result(i+x.i); return result; } int main(){ Number x(1),y; //调用一个参数的构造函数构造x,调用默认值的构造函数构造y y = x+2; //数字2强制类型转换,生成临时对象,用一个参数的构造函数构造来转换,无名变量(2) //重载运算符+进行计算,用一个参数的构造函数构造新对象,并在运算结束后析构,重载运算符+中不涉及无名变量等问题 //如果将运算符+重载的内容直接改成 i=x.i; return *this; 则显示结果中Construtor:D3这一句改成Copy Number:D3 //运算符=进行y的浅拷贝 return 0; }
结果:
Constructor Number:A1
Constructor Number:B0
Constructor Number:C2
Constructor Number:D3
Destructor Number:D3
Destructor Number:C2
Destructor Number:D3
Destructor Number:A1
例4:
#include<iostream> #include <cmath> using namespace std; class point{ int x,y; public: point(int xx=0,int yy=0){ x= xx; y =yy; cout<<"point的构造函数被调用\n"; } point (point &p){ x = p.x; y = p.y; cout<<"point的复制构造函数被调用\n"; } int GetX(){ return x;} int GetY(){ return y;} }; class line{ point p1, p2; double len; public: line (point xp1,point xp2):p1(xp1),p2(xp2){ cout<<"line的构造函数被调用\n"; double x = double (p2.GetX()-p1.GetX()); double y = double (p2.GetY()-p1.GetY()); len = sqrt(x*x+y*y); //在私有数据中被定义,所以类外(class,不是对象)对len进行运算时,要用成员函数调用 } line (line &l); double GetLen(){ return len;} }; int main(){ point myp1(1,1),myp2(4,5); //myp1 两个参数的构造函数 myp2两个参数的构造函数 line line0(myp1,myp2); //myp1 做实参传给line0的复制构造函数line 中的xp1时,xp1 通过复制构造函数得到myp1的值 //xp1 做实参传给p1的复制构造函数point中的参数p时,p通过复制构造函数得到xp1的值 //myp2 xp2 p2 的类似上述过程,所以这边一共调用了4次复制构造函数 cout<<"The length of the line0 is :"; cout<<line0.GetLen()<<endl; //计算 return 0; }
结果:
point的构造函数被调用
point的构造函数被调用
point的复制构造函数被调用
point的复制构造函数被调用
point的复制构造函数被调用
point的复制构造函数被调用
line的构造函数被调用
The length of the line0 is :5
例5:
#include<iostream> using namespace std; class Number{ int i; public: Number(int x=0){ i=x; cout<<"Constructor Number:"<<i<<endl; } ~Number(){ cout<<"Destructor Number:"<<i<<endl; } Number operator +(const Number &x){ Number result; cout<<"Add Number"<<endl; result.i = i+x.i; return result; } }; int main(){ Number x(1),y(2); //构造函数x(1)和构造函数y(2) y=x+y; //运算符+重载中默认值构造函数 //析构运算符+中的对象 //运算符=浅拷贝 //析构y 和 x return 0; }
结果:
Constructor Number:1
Constructor Number:2
Constructor Number:0
Add Number
Destructor Number:3
Destructor Number:3
Destructor Number:1
例6:构造函数的作用是初始化,构造初始化列表先于构造函数函数体执行。
#include <iostream> using namespace std; class data{ int x; public: data(int x){ data::x=x; cout<<"class data"<<endl; } }; class a{ data d1; public: a(int x):d1(x){ cout<<"class a"<<endl; } }; class b:public a{ data d2; public: b(int x):a(x),d2(x){ cout<<"class b"<<endl; } }; class c:public b{ public: c(int x):b(x){ cout<<"class c"<<endl; } }; int main(){ c obj(5); return 0; }
结果:
class data
class a
class data
class b
class c
例7
#include <iostream> using namespace std; class Sample{ int x,y; public: Sample(int a=1,int b=1){ x=1,y=b; disp(); } Sample(Sample &s){ x=s.x; y=s.y; cout<<"in copy construct"<<endl; } Sample &operator=(Sample &s){ x=s.x; y=s.y; cout<<"in operator = "<<endl; return *this; } ~Sample(){ if(x==y){ cout<<"x==y"<<endl; }else{ cout<<"x!=y"<<endl; } } void disp(){ cout<<"x="<<x<<"y="<<y<<endl; } friend void ms(Sample s); }; void ms(Sample s){ s.x=s.y; } int main(){ Sample s1(2,3); //调用两个参数的构造函数 Sample s2 = s1; //调用复制构造函数,利用s1构造s2 ms(s2); //调用复制构造函数,利用s2构造无名对象,参加后续函数运算的是无名构造对象 //完成ms函数后,无名构造对象的x和y同,但是s2的值不受改变 //析构无名变量,析构s2,析构s1 return 0; }
结果:
x=1y=3
in copy construct
in copy construct
x==y
x!=y
x!=y
例8:
#include <iostream> using namespace std; class A{ public: virtual void print(){ cout<<"A::print"<<endl; } }; class B:public A{ public: void print(){ cout<<"B::print"<<endl; } }; class C:public B{ public: void print(){ cout<<"C::print"<<endl; } }; void print(A a){ //参数的类型是A ,相对于int float 之类的 a.print(); } int main(){ C c; print(c); //c是C类型的,和A类型不符合,所以往C的父类中找相对应的函数 return 0; }
结果:
A::print