-3

标题只是我对以下示例感到困惑的几件事之一:

struct A {
    A() {
        std::cout << "Default constructor of A" << std::endl;
    }
    A(const A &) {
        std::cout << "Copy constructor of A" << std::endl;
    }
};

struct B : private A {
    // using A::A; // does not help for question 2.    
};

int main() {
    A a;
    B b;
    B c(b); // Does not work with `a` as an argument
    return 0;
}

此示例输出:

Default constructor of A
Default constructor of A
Copy constructor of A

问题:

  1. 的私有继承构造函数如何在B中可用main?这个问题与本文中的问题类似但问题是关于从内部使用该构造函数B,这是不同的。
  2. 被调用的复制构造函数接受一个const A &参数。但是,如果我写B c(a)而不是B c(b),则代码不会编译。怎么来的?(请注意,取消注释using指令B没有帮助)。
  3. 这是次要的,但仍然如此。为什么编译器没有警告我未使用的变量ac

问题 2 已转到另一个职位

4

2 回答 2

2
  1. 您不是直接调用 A 的构造函数,而是 B 的默认构造函数为您执行此操作。如果这有任何不同,您将永远无法构造任何私有继承任何东西的类。

  2. 这是因为 B 没有类型 A 的复制构造函数。唯一可以在此处应用的构造函数是类型 B 的(默认)复制构造函数,它将 B 作为参数。

构造函数绑定到它们的类,它们不像函数那样继承。如何解释... 基本目标是确保每个类始终构造完整。因此,要构造任何类型的 A(无论是独立的,还是作为 B 的一部分),必须运行 A 的构造函数。类似地,要构造 B 类的对象,必须运行 B 的构造函数。如果您“继承” A::A() 构造函数,您将能够构造未完全构造的 B。在这种情况下,A::A() 构造函数没有运行 B 的构造序列的任何部分,从而使 B 处于无效状态。

让我们尝试一些不同的来源。我们保持 A 不变,并像这样更改 B:

struct B : private A {
    B () { val = 42; }
    void foo () { if (val != 42) abort (); }

    using A::A;

    int val;
};

现在假设我们,呃,获得一个 B 而不构造它:

B b (a); // illegal, but for the sake of argument.
b.foo ();

我们已经指定我们使用 A::A 构造函数来构造这个 B,因此将执行的唯一代码是 A::A()。特别是, B::B() 没有执行,所以 val 将具有当时堆栈上存在的任何值。它是 42 的机会是 2^32 中的 1,换句话说,不太可能。

调用 B.foo() 会发生什么?对象不在有效状态(val 不是 42),因此应用程序中止。哎呀!

这当然是一个人为的例子,但它表明使用非构造对象是一件非常糟糕的事情,因此该语言会阻止您创建任何此类对象。

  1. 它们没有被使用。构造函数中发生了各种各样的活动(写入 cout),这些活动不能简单地消除。

这种设计模式在 C++ 中多次出现,例如在 std::mutex 中。只需声明一个锁就足以进行加锁和解锁,但不需要在声明后引用锁。由于这是一种常见的设计模式,因此警告是不合适的。

只有当编译器可以证明构造和析构一个局部变量没有副作用,并且发现它没有被使用时,你可能会看到一个警告(取决于编译器)。

于 2016-07-31T13:58:08.730 回答
1

为什么 B 的私有继承构造函数在 main 中可用?

他们不是。

然而,B它们本身是可用的,因为它们已经被继承了,并且是 B 调用了继承的基本构造函数。

显然,如果不是这样,那么私有继承将毫无用处,因为您永远无法实例化私有继承类。

他们被调用,输出就是证明

不,这不对。你在草率下结论。有中间函数调用(在 中隐式定义的构造函数B)不会产生您没有考虑到的输出。

被调用的复制构造函数接受一个 const A & 参数。但是,如果我写 B c(a) 而不是 B c(b),则代码不会编译。怎么来的?

不,它没有。B您的代码行调用带有参数的复制构造const B&函数。B没有带const A&参数的复制构造函数。

该复制构造函数又在内部调用基的复制构造函数,产生您看到的输出。

构造函数不会以您似乎相信的方式继承。

这是次要的,但仍然如此。为什么编译器没有警告我未使用的变量 a 和 c?

因为它们没有被使用。他们的建设做了一件事(创造了输出)。

于 2016-07-31T13:57:14.767 回答