20

我知道,如果您在无参数构造函数的初始化列表中留下一个成员,则将调用该成员的默认构造函数。

复制构造函数是否同样调用成员的复制构造函数,还是它们也调用默认构造函数?

class myClass {
  private:
    someClass a;
    someOtherClass b;
  public:
    myClass() : a(DEFAULT_A) {} //implied is b()
    myClass(const myClass& mc) : a(mc.a) {} //implied is b(mc.b)??? or is it b()?
}
4

8 回答 8

31

显式定义的复制构造函数不会为成员调用复制构造函数。

当您进入构造函数的主体时,该类的每个成员都将被初始化。也就是说,一旦您到达{您就可以保证您的所有成员都已初始化。

除非指定,否则成员会按照它们在类中出现的顺序进行默认初始化。(如果不能,则程序格式不正确。)因此,如果您定义了自己的复制构造函数,那么您现在可以根据需要调用任何成员复制构造函数。

这是一个小程序,您可以在某处复制粘贴并弄乱:

#include <iostream>

class Foo {
public:
    Foo() {
        std::cout << "In Foo::Foo()" << std::endl;
    }

    Foo(const Foo& rhs) {
        std::cout << "In Foo::Foo(const Foo&)" << std::endl;
    }
};

class Bar {
public:
    Bar() {
        std::cout << "In Bar::Bar()" << std::endl;
    }

    Bar(const Bar& rhs) {
        std::cout << "In Bar::Bar(const Bar&)" << std::endl;
    }
};

class Baz {
public:
    Foo foo;
    Bar bar;

    Baz() {
        std::cout << "In Baz::Baz()" << std::endl;
    }

    Baz(const Baz& rhs) {
        std::cout << "In Baz::Baz(const Baz&)" << std::endl;
    }
};

int main() {
    Baz baz1;
    std::cout << "Copying..." << std::endl;
    Baz baz2(baz1);
}

按原样打印:

在 Foo::Foo()
在酒吧::酒吧()
在 Baz::Baz()
复制...
在 Foo::Foo()
在酒吧::酒吧()
在 Baz::Baz(const Baz&)

请注意,它默认初始化Baz.

通过注释掉显式复制构造函数,例如:

/*
Baz(const Baz& rhs) {
    std::cout << "In Baz::Baz(const Baz&)" << std::endl;
}
*/

输出将变为:

在 Foo::Foo()
在酒吧::酒吧()
在 Baz::Baz()
复制...
在 Foo::Foo(const Foo&)
在 Bar::Bar(const Bar&)

它在两者上调用复制构造函数。

如果我们重新引入Baz的复制构造函数并显式复制单个成员:

Baz(const Baz& rhs) :
    foo(rhs.foo)
{
    std::cout << "In Baz::Baz(const Baz&)" << std::endl;
}

我们得到:

在 Foo::Foo()
在酒吧::酒吧()
在 Baz::Baz()
复制...
在 Foo::Foo(const Foo&)
在酒吧::酒吧()
在 Baz::Baz(const Baz&)

如您所见,一旦您明确声明了一个复制构造函数,您就负责复制所有类成员;现在是你的构造函数。

这适用于所有构造函数,包括移动构造函数。

于 2009-04-16T04:26:29.347 回答
2

对于任何具有默认构造函数的成员变量,如果您没有将对该成员变量的任何其他构造函数调用显式添加到初始化列表中,则会调用该默认构造函数。

于 2009-04-16T04:27:05.150 回答
2

有关详细信息,请参阅:C++ 中是否存在隐式默认构造函数?

短的:

  • 编译器生成的“默认构造函数”:使用每个成员的默认构造函数。
  • 编译器生成的“复制构造函数”:使用每个成员的复制构造函数。
  • 编译器生成的“赋值运算符”:使用每个成员的赋值运算符。
于 2009-04-16T05:40:46.347 回答
1

是的。演员就是演员。

于 2009-04-16T04:08:33.963 回答
1

复制构造函数没有什么神奇之处,除了编译器会在需要时添加它。但在它实际运行的方式上,并没有什么特别之处——如果你没有明确地说“使用这样那样的构造函数”,它将使用默认值。

于 2009-04-16T04:30:06.220 回答
1

VC9 中没有。不确定其他人。

// compiled as: cl /EHsc contest.cpp
//
//    Output was:
//    Child1()
//    -----
//    Child1()
//    Child2()
//    Parent()
//    -----
//    Child1(Child1&)
//    Child2()
//    Parent(Parent&)

#include <cstdio>

class Child1 {
    int x;
public:
    static Child1 DEFAULT;

    Child1(){
        x = 0;
        printf("Child1()\n");
    }

    Child1(Child1 &other){
        x = other.x;
        printf("Child1(Child1&)\n");
    }
};

Child1 Child1::DEFAULT;

class Child2 {
    int x;
public:
    Child2(){
        x = 0;
        printf("Child2()\n");
    }

    Child2(Child2 &other){
        x = other.x;
        printf("Child2(Child2&)\n");
    }
};

class Parent {
    int x;
    Child1 c1;
    Child2 c2;

public:
    Parent(){
        printf("Parent()\n");
    }

    Parent(Parent &other) : c1(Child1::DEFAULT) {
        printf("Parent(Parent&)\n");
    }
};

int main(){
    printf("-----\n");
    Parent p1;
    printf("-----\n");
    Parent p2(p1);

    return 0;
}
于 2009-04-16T05:25:55.603 回答
1

根据基调用构造函数的启动方式,成员的构造函数将以相同的方式调用。例如,让我们从:

struct ABC{
    int a;
    ABC() : a(0)    {   printf("Default Constructor Called %d\n", a);   };

    ABC(ABC  & other )  
    {
        a=other.a;
        printf("Copy constructor Called %d \n" , a ) ;
    };
};

struct ABCDaddy{
    ABC abcchild;
};

您可以进行以下测试:

printf("\n\nTest two, where ABC is a member of another structure\n" );
ABCDaddy aD;
aD.abcchild.a=2;

printf( "\n Test: ABCDaddy bD=aD;  \n" );
ABCDaddy bD=aD; // Does call the copy constructor of the members of the structure ABCDaddy ( ie. the copy constructor of ABC is  called)

printf( "\n Test: ABCDaddy cD(aD); \n" );
ABCDaddy cD(aD);    // Does call the copy constructor of the members of the structure ABCDaddy ( ie. the copy constructor of ABC is  called)

printf( "\n Test: ABCDaddy eD; eD=aD;  \n" );
ABCDaddy eD;
eD=aD;          // Does NOT call the copy constructor of the members of the structure ABCDaddy ( ie. the copy constructor of ABC is not called)

输出:

Default Constructor Called 0

Test: ABCDaddy bD=aD;
Copy constructor Called 2

Test: ABCDaddy cD(aD);
Copy constructor Called 2

Test: ABCDaddy eD; eD=aD;
Default Constructor Called 0

享受。

于 2011-08-31T17:45:34.100 回答
0

当编译器提供默认的 cctor 时,你认为编译器对成员变量做了什么?它复制构造它。

同样,如果 cctor 是用户定义的,并且如果遗漏了一些成员,则这些成员不能未初始化。类不变量是在构造过程中建立的,并且必须不断维护。因此,编译器会为您执行此操作。

于 2009-04-16T04:28:44.990 回答