【问题标题】:C++ copy Constructor and default constructorC++复制构造函数和默认构造函数
【发布时间】:2020-05-14 21:54:27
【问题描述】:

我正在学习 c++,但发现了一个我不太了解的输出。

#include <iostream>
using namespace std;

class A{
    public:
        A(){ cout << "A+" << endl;}
        A(const A&){ cout << "A(A)" << endl;}
        ~A(){cout << "A-" << endl;}
};

class B{
    public:
        B(){ cout << "B+" << endl;}
        B(const B&){cout << "B(B)" << endl;}
        ~B(){cout << "B-" << endl;}
    private:
        A a;
};

class C : public A{
    public:
        C(const B& b) : b1(b) { cout << "C+" << endl;}
        ~C(){ cout << "C-" << endl;}
    private:
        B b1,b2;
};

void test(A a){
    A m(a);
}

int main(){
    B b;
    C c(b);
    test(c);
    return 0;

}

输出是

A+
B+
A+
A+
B(B)
A+
B+
C+
A(A)
A(A)
A-
A-
C-
B-
A-
B-
A-
A-
B-
A-

我的意思是第一个,B 去默认看到一个我们从类型 A 中得到一个成员然后去 A 那就是 A+ 然后返回 B 并打印 B+。这就是B b;而不是C c(b)它去C,看到它的公共A去A并打印A+,然后返回看到我们有一个成员B b1,b2去B并且B有一个成员A并且去agean A 并打印 A+ 而我不明白为什么 B(B) ?在此 B(B) 之后我什么都不懂.. 我尝试调试它但它对我没有多大帮助,也许有人可以解释为什么会这样?

【问题讨论】:

  • 如果你将输出与行匹配(如 cout
  • C构造函数初始化列表中,b1(b)b1成员的copy-initialization。因此它调用B 复制构造函数。
  • @Someprogrammerdude 但为什么它不在下一行打印C+?让我感到困惑的是``` C(const B& b)```它说copyconstructor等待一个B对象?和b1(b)调用copyconst。来自 B?好混乱
  • 可能有点不相关,但是您可以通过简单地使用打印函数全名的非标准宏(即使它是模板)来使输出更容易理解。用cout&lt;&lt;__PRETTY_FUNTION__&lt;&lt;endl; 替换所有cout&lt;&lt;... 并享受。

标签: c++ class constructor derived-class


【解决方案1】:

让我们仔细看看C 构造函数(稍微重新格式化):

C(const B& b)
    :
    b1(b)
{
    cout << "C+" << endl;
}

首先将调用A 构造函数,因为它是C 的基类。这将打印A+

然后b1 成员将被复制构造,由于B::a 成员将首先打印A+,然后在B 复制构造函数主体中打印B(B)

然后将默认构造b2 成员,它将打印A+(同样是因为B::a 成员),然后是B+

然后C 构造函数主体将运行,它将打印C+


C 构造函数真的等同于这个(添加了 cmets):

C(const B& b)
    : A(),      // Prints A+
      b1(b),    // Prints A+ and B(B)
      b2()      // Prints A+ and B+
{
    cout << "C+" << endl;    // Prints C+
}

希望这会让我们更容易看到发生了什么。

【讨论】:

    【解决方案2】:

    如果我正确理解了您的问题,您正在尝试理解输出

    A+
    A+
    B(B)
    A+
    B+
    C+
    

    对应于这个声明

    C c(b);
    

    类 C 有基类 A

    class C : public A{
    

    所以调用A类的构造函数

    A+
    

    然后创建数据成员 b1

    C(const B& b) : b1(b) { cout << "C+" << endl;}
    

    类B又拥有数据成员A

    class B{
        public:
            B(){ cout << "B+" << endl;}
            B(const B&){cout << "B(B)" << endl;}
            ~B(){cout << "B-" << endl;}
        private:
            A a;
    };
    

    所以当B类的复制构造函数被调用时,数据成员a被创建

    A+
    B(B)
    

    类 C 多了一个类 B 的数据成员。它是数据成员 b2。 所以这些构造函数被调用

    A+
    B+
    

    最后构造函数 C 的主体得到控制

    C+
    

    析构函数以与创建对象的顺序相反的顺序获得控制。

    所以对象c的析构函数输出如下所示

    C-
    B-
    A-
    B-
    A-
    A-
    

    您可以通过对程序的微小改动使程序输出更清晰。

    例如

    #include <iostream>
    using namespace std;
    
    class A{
        public:
            A(){ cout << "A+" << endl;}
            A(const A&){ cout << "A(A)" << endl;}
            ~A(){cout << "A-" << endl;}
    };
    
    class B{
        public:
            B() : i( n++ ) { cout << "B+" << ' ' << i << endl;}
            B(const B&) : i( n++ ) {cout << "B(B)" << ' ' << i << endl;}
            ~B(){cout << "B-" << ' ' << i << endl;}
        private:
            size_t i;
            static size_t n;
            A a;
    };
    
    size_t B::n;
    
    class C : public A{
        public:
            C(const B& b) : b1(b) { cout << "C+" << endl;}
            ~C(){ cout << "C-" << endl;}
        private:
            B b1,b2;
    };
    
    void test(A a){
        A m(a);
    }
    
    int main(){
        B b;
    
        std::cout << '\n';
    
        C c(b);
    
        std::cout << '\n';
    
        test(c);
    
        std::cout << '\n';
    }
    

    这个更新程序的程序输出是

    A+
    B+ 0
    
    A+
    A+
    B(B) 1
    A+
    B+ 2
    C+
    
    A(A)
    A(A)
    A-
    A-
    
    C-
    B- 2
    A-
    B- 1
    A-
    A-
    B- 0
    A-
    

    【讨论】:

    • 噢,谢谢,我坐了 2 天.. 现在我明白了。但是,如果我做test(c);,那么只有一件事不是很清楚,为什么 a 的复制构造函数是双倍的?我的意思是void test(A a){ A m(a); } 测试是等待一个 A 对象和 A m(a) 它只复制一次?
    • @Jüngealles 有两次调用复制构造函数。第一次创建 A 类型的参数,第二次在函数内部创建本地对象。
    • 嗯,我不太明白。 void test(A a) 正在等待争论.. 和 void foo(int i) 一样,对吧?然后A m=a 或者和A m(a)不一样?
    • @Jüngealles 在这次通话中 test(c);使用复制构造函数从派生类 c 的对象创建类型 A 的临时对象。在此声明中的函数内 A m(a);第二次显式调用了复制构造函数。
    猜你喜欢
    • 2016-03-25
    • 1970-01-01
    • 2016-03-24
    • 2011-07-15
    • 2014-05-15
    • 1970-01-01
    • 1970-01-01
    • 2014-03-24
    相关资源
    最近更新 更多