在抽象类层次结构中操作符=的复杂继承

Tricky inheritance of operator= in abstract class hierarchy

本文关键字:复杂 继承 操作符 抽象类 层次结构      更新时间:2023-10-16

我有这个类层次结构,我试图添加operator=:

class A
{
public:
    virtual void someFunction() = 0;
    virtual A& operator=(const A&) = 0;
};
class B : public A
{
public:
    void someFunction() {
        //implementation
    }
    A& operator=(const A& o)
    {
        *ptr = *o.ptr;
        return *this;
    }
private:
    A* ptr;
};
class C : public A
{
public:
    void someFunction() {
        //implementation
    }
    A& operator=(const A& o)
    {
        data = o.data;
        return *this;
    }
private:
    int data;  //NOTE: different members that needs to be copied in the operator
};

我明白为什么这不起作用。我在B中有一个私有成员(它需要在那里)和一个需要重写的函数A&operator=(const A&)。问题是o是A型的,没有指针ptr

我已经尝试将0动态转换为类型B,但是

  1. 不能工作,因为它是常量,
  2. 似乎不安全(如果rhs是C类)

C类也有同样的问题。有什么切菜刀的办法吗?

解释为什么我需要这样做:

class superClass
{
public:
  superClass& operator=(const superClass& o)
  {
    *some_A_type = *o.some_A_type;
  }
private:
  A* some_A_type;
};

实际上,我想要的是superClass的操作符=。我不确定在哪里或如何修复它

你应该重新考虑你最初的类设计。

你也应该明白:

  • 操作符多态性(a + b适用于std::stringint)
  • 数据类型本身不能为polymorph,因为应该定义内存布局
  • 什么是抽象类和/或接口
  • 也许静态多态性也会有用

首先试着想象在A类的任意类的任意对象之间赋值意味着什么。也就是说,为了将B的对象存储在C的对象中,我们应该改变C对象的状态,使其特征等同于B的原始对象。这可以通过在A的所有后代之间拥有共同的内存布局(即所有后代存储相同的数据)或通过引用原始对象等其他方式暴露相同的行为来实现。

注意virtual void someFunction()的行为也应该被复制。

让我们试着最大限度地利用你的样品:

// our interface
struct A {
    virtual void someFunction() = 0;
    // no polymorphic assignment
};  
struct B : A {
    void someFunction();
    B &operator=(const A &o)
    { ptr = &o; return *this; }
private:
    A *ptr;
}   
struct C : A {
    void someFunction();
    A &operator=(const C &o)
    { data = o.data; return *this; }
private:
    int data;
};
C c, c2;
B b;
A &a = c;
b = c; // ok
b = a; // ok
c = c2; // ok
c = b; // wrong

或者如果你仍然想要多态分配:

// interface. descendants are responsible for maintaining LSP
struct A {
    void someFunction()
    { cout << data(); }
    virtual int getData() const = 0;
    // assignment should result in copying chars and making getData() to behave like in original object
    virtual A &operator=(const A &o) = 0; 
};  
struct B : A {
    int getData() const { return ptr->getData(); }
    A &operator=(const A &o)
    { ptr = &o; return *this; }
private:
    const A *ptr;
};
struct C : A {
    int getData() const { return data; }
    A &operator=(const A &o)
    { data = o.getData(); return *this; }
private:
    int data;
};

注:最后一个在现实世界中可能不需要的变体

在toimcnamobi提出的类似问题中找到:

class B : public A
{
public:
  virtual A& operator=(const A& p)
  {
    *ptr = *o.ptr;
    return *this;
  }

  virtual B& operator=(const B& p)
  {
    //throw exception
  }
};