构造,析构,复制构造,重载=,和自动创建无名变量的问题(习题)

2 篇文章 0 订阅

关于构造,析构,复制构造,=,和自动创建无名变量

总结:

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








  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值