通过另一个派生 class 的对象初始化派生 class 的基础部分的构造函数

Constructor to initialize base part of derived class by object of another derived class

假设我有一个基数 class 和 2 个派生的 classes:

class Base {
   public:
      Base() : m_base(0) { }
   private:
      int m_base; 
};

class Derived1 : public Base {
   public:
      Derived1() : Base(), m_d1(1) { }
   private:
      int m_d1;
};

class Derived2 : public Base {
   public:
      Derived2(): Base(), m_d2(2.5) { }
   private:
      double m_d2;
};

我现在想要一个重载的构造函数来构造一个 Derived2 的实例,方法是用一个 Derived1 的实例初始化它的基础部分,我遇到了一些不同的方法:

  1. 指向 Derived1 + dynamic_cast + 基础 class 初始化列表中的复制构造函数的指针:

    Derived2(Derived1 *d1) : Base(*(dynamic_cast<Base*>(d1))), m_d2(3.5) { }

    显然这有取消引用无效指针的问题

  2. 调用时引用Base并投Derived1

    Derived2(const Base &base) : Base(base), m_d2(3.5) { }
    // ...
    Derived1 d1 = Derived1();
    Derived2 d2 = Derived2(static_cast<Base>(d1));
    
  3. 首先调用Base的默认构造函数,然后初始化每个成员:

    Derived2(Derived *d1) : Base(), m_d2(3.5) {
       if (d1) {
           m_base = d1->base();
       }
     }
    

    但这需要访问 Derived1 的成员以及 Base 的成员才能成为 protected

当然还有另一种更好的方法 - 那么哪种方法最好,为什么?

您不需要转换为基类型。

你说你想做的最直接的翻译是

Derived2(const Derived1& d1): Base(d1), m_d2(2.5) { }

然后你只需要

Derived1 d1;
Derived2 d2(d1);

如果您想接受从 Base 派生的任何类型:

Derived2(const Base& b): Base(b), m_d2(2.5) { }
  1. Pointer to Derived1 + dynamic_cast + base class copy-constructor within initializer list

不需要指针,不需要动态转换,也不需要将参数限制为仅 Derived1.

  1. Reference to Base and cast Derived1 when calling

这很好,除了强制转换是多余的。对象可以隐式转换为其基数。

  1. Call default constructor of Base first and then initialize every single member

这毫无意义地复杂化,并且在 base 不是默认可初始化的情况下不是一个选项。


另一种方法是按值传递基数,然后从中移动:

Derived2(Base base) : Base(std::move(base))

这允许避免从右值参数复制。这对于示例中的琐碎 Base 不是特别有用,但对于一些复制速度较慢的真实示例可能会快得多。