从基类调用复制和赋值运算符以在 C++ 中创建继承的类实例

Calling copy and assignment operators from base class to create inherited class instances in C++

提问人:carce-bo 提问时间:7/13/2022 最后编辑:carce-bo 更新时间:7/14/2022 访问量:407

问:

我有以下类(例如):

class A {

   public:
   A(void) : i(0) {}
   A(int val) : i(val) {} 
   A(const A& other) : i(other.i) {}
   A& operator=(const A& other) {
       i = other.i;
       return *this;
   }

   int i;
};

class B : public A {

   public:
   B(void) : A(), j(0) {};
   B(const B& other) : A(other), j(other.j) {}
   B(int i, int j) : A(other.i), j(other.j) {}
   B& operator=(const B& other) {
      A::operator=(other);
      j = other.j;
      return *this;
   }
   
   int j;
};

我的问题是,鉴于 中的重载和复制构造函数,如果我希望能够从已经初始化的实例中创建 的实例,或者将 的现有实例分配给 的现有实例,是否有必要在 上定义另一个复制构造函数并使用以下签名?operator=BBAABBoperator=

B(const A& other);
B& operator=(const A& other);

目标是能够仅使用基类信息实例化/赋值派生类实例。
PS:我正在使用 C++98 并且无法使用任何更新的标准。

C++ 继承 运算符重载 复制构造函数 C++98

评论


答:

0赞 utnapistim 7/13/2022 #1

目标是能够仅使用基类信息实例化/赋值派生类实例。

你的目标对我来说听起来很可疑。

通常在实践中,您有两种不同的方案:

  • 数据对象(不需要继承层次结构)
  • 行为对象(通过继承实现相同的接口)。

数据对象(因为它们没有公共基类)实现实例化和赋值(复制构造函数和赋值运算符)。

行为对象(类层次结构中的对象)不能以泛型方式实现基类对象的赋值(如何处理派生类中存在但基类中不存在的成员变量?为它们指定默认值?保持它们不变?)。

也就是说,您应该使用与复制构造函数和赋值不同的 API,以避免混淆和隐式强制转换。

也就是说,如果您同时拥有:

B& operator=(const B&);
B& operator=(const A&);

那么当代码从 B 实例分配时,这是不明确的(因为编译器可以调用它们中的任何一个)。

您可以添加一个 .这也将使其更加明确。B::copy_common_values(const A&);

如果您尝试解决 x-y 问题,还可以查找原型设计模式。

评论

0赞 carce-bo 7/13/2022
代码中的对象 A 和 B 都是数据对象。B 只是 A 的数据扩展。因为只有一个类 A 以及所有 B 类信息似乎不是最佳选择,因为 A 实例通常不需要 B 字段。然后,我的代码从 A 创建 B 实例,因为它扩展了 A 中的信息。但是省略当时的标准 B 复制构造函数似乎不是一个解决方案。B(const &A other)
0赞 carce-bo 7/13/2022
另外,如果我使用引用,为什么会模棱两可?如果一个实例被声明,然后分配给其他实例,为什么编译器会认为右侧是一个实例,如果它被明确初始化为一个实例,并且有一个显式的运算符?BBAB
0赞 utnapistim 7/13/2022
Objects A and B in my code are both data objects. B is just a data extension of A.考虑将 A 的实例作为 B 的成员,并在这种情况下避免继承?(只是一个想法 - 我不知道它是否适用于你的问题)。
0赞 carce-bo 7/14/2022
我考虑过这一点,但我想首先探索其他可能性。我最终可能会这样做,因为这似乎是一个更直接的解决方案。谢谢你的帮助。
1赞 Goswin von Brederlow 7/14/2022 #2

是的,你必须定义这样的东西。

B(常量 A& 其他);

这将允许构造 .这也将允许通过隐式转换为然后分配的方式进行赋值。因此,仅此一项就足够了。但是你会得到一个额外的副本。BAABAB

B& operator=(const A& other);

这样可以提高分配效率,因为您可以避免临时 .这还应该允许分配可以隐式转换为如下内容的内容:ABBA

B b = 1;

如果你不想这样做,你可能不得不添加一些.C++98 有显式吗?这是上个千年的情况。explicit

注意:在现代 C++ 中,由于复制省略,并且您可以使用移动语义和完美的转发引用,这将更有效。

评论

0赞 carce-bo 7/14/2022
C++98 只允许构造函数为 。我确实实现了(虽然在这个答案之前,只是尝试了一下)额外的复制构造函数和赋值运算符,并且它按预期工作。谢谢你的帮助。explicit