提问者:小点点

从没有初始值设定项列表的类构造另一个类对象


#include <iostream>
class A {
 public:
  A(){};
  A(A& b) { std::cout << "l\n"; };
};

class B {
 public:
  A x;
  A p;
  B() {}
  B(A c) {
    this->x = c;
    this->p = c;
    std::cout << "k\n";
  }
};

int main(void) {
  A b;
  B x(b);
}

我现在知道这样的事情是不可能的,要在类B中创建对象X和p,我需要通过初始化器列表来创建它。所以只有像这样的方法才能奏效:

#include <iostream>
class A {
 public:
  A(){};
  A(A& b) { std::cout << "l\n"; };
};

class B {
 public:
  A x;
  A p;
  B() {}
  B(A c): x(c),p(c) {
    std::cout << "k\n";
  }
};

int main(void) {
  A b;
  B x(b);
}

我的问题是,第一种情况到底发生了什么?程序编译时没有错误,但没有(假定)调用复制构造函数。另外,根据我的理解,如果b的复制构造函数有,c作为参数,那么复制构造函数也需要在c上调用(将b复制到c中),然后将c复制到其他一些复制构造函数中,等等。那么这难道不可能导致无休止的递归吗?


共2个答案

匿名用户

this->x=c不会调用复制构造函数,它将调用复制赋值运算符。

A(A& b) { std::cout << "copy constructor\n"; };
A& operator=(A const& b) { std::cout << "copy assignment\n"; }

匿名用户

在执行构造函数的主体之前初始化成员。

如果不提供初始值设定项:

struct C {
    A a;
    C() = default;
};

则默认初始化memebrs。即:a通过调用默认构造函数来构造。

如果在构造函数的主体中赋值:

struct D {
    A a;
    D(A x) {
       a = x;
    }
};

则首先默认初始化成员a,然后由赋值覆盖。那有点浪费。

如果在memebr初始值设定项列表中提供非默认初始值设定项:

struct E {
    A a;
    E(A x) : a(x) {}
};

则成员a未默认初始化。相反,它是通过制作x的副本来构造的。

更多详细信息,请访问:https://en.cppreference.com/W/cpp/language/constructor

您的第一个版本在技术上是正确的。不清楚你说的“我知道现在这样的事情是不可能的”是什么意思。您在复制构造函数中看不到输出,因为它没有被调用。将cout添加到复制分配中,以查看相应的输出。