class 中的多态函数正在实现抽象 class

Polymorphic function in class which is implementing abstract class

class Eq
{
public:
    virtual bool operator==(Eq operand) = 0;
};

class Day : public Eq
{
public:
    enum DAY
    {
        Monday,
        Tuesday,
        Wednesday,
        Thursday,
        Friday,
        Saturday,
        Sunday
    } day;
    Day(DAY init_day) : day(init_day){}
    bool operator==(Day operand)
    {
        return day == operand.day;
    }
};

int main()
{
    Day d1(Day::Monday);
    Day d2(Day::Monday);
    d1 == d2;
    return 0;
}

这是我试图实现的代码。 Class Eq 的工作方式类似于 JAVA 的接口。它只有一个成员函数,operator==。运算符== 接受一个与 class 相同类型的操作数,后者推导出 Eq class。例如,class Day 派生Eq,所以它必须实现operator== 取Day 类型参数。

问题来了。首先,两个 operator== 函数都有不同的签名。所以编译器认为它们不是相同的函数,而是重写的函数。其次,如果此代码中的任何函数采用 Eq class 参数,则编译器会出错,因为抽象 class 的实例不可用。

原来是这个问题。如何使 T class 中的 operator== 函数接受 T class 参数,其中 T 是 Eq class?

的实现

您可以在 Eq 中引入类型参数 T 并从 Eq<Day> 派生 Day 以强制执行所需的 operator==.[=15 签名=]

您可以使用 CRTP:

template <typename DerivedType>
class Eq
{
public:
    virtual bool operator==(DerivedType operand) = 0;
};

class Day : public Eq<Day>
{
public:
    enum DAY
    {
        Monday,
        Tuesday,
        Wednesday,
        Thursday,
        Friday,
        Saturday,
        Sunday
    } day;
    Day(DAY init_day) : day(init_day){}
    bool operator==(Day operand)
    {
        return day == operand.day;
    }
};

您可以通过发送参考文献来做到这一点。

class Eq
{
public:
    virtual bool operator==(Eq& operand) = 0; // Changed to reference
};

class Day : public Eq
{
public:
    enum DAY
    {
        Monday,
        Tuesday,
        Wednesday,
        Thursday,
        Friday,
        Saturday,
        Sunday
    } day;
    Day(DAY init_day) : day(init_day){}
    bool operator==(Eq& operand) // Changed to reference of Eq.
    {
        const Day* other = dynamic_cast<Day*> (&operand);
        if (other == nullptr) // Checking if the operand is of Day type.
            return false; // If not, those two objects cannot be the same.
        return day == other->day; // Do the comparison. 
        // Note the '->' instead of '.' since 'day' is a pointer.
    }
};

与 Java(我想您更熟悉后者)相比,您遗漏了一些有关 C++ 工作方式的关键点。

  1. 要进行虚拟覆盖,您必须具有相同的方法签名。
  2. 为避免切片,您需要发送引用或指针,而不是堆栈上的对象。
  3. 最后,发送值可能会占用大量内存(与引用或指针相比)。

这里有几个我发现的关于在处理继承时如何进行 operator== 重载的好链接。 (他们还谈到了 public-non-virtual/non-public-virtual 的讨论。)

Equality Test for Derived Classes in C++

What's the right way to overload operator== for a class hierarchy?

您的方法有两个主要缺陷:

  • operator== 签名 for DayEq 的签名不匹配,因此无法使用。
  • 您按值传递运算符的操作数。这意味着将有 slicing(即传递的对象可能会丢失所有不在 Eq 中的成员,今天是)

已经有很好的模板解决方案提出来了,对于这类问题很方便。为了完整起见,我建议您使用无模板的替代方案。

第一次机会Eq

class Eq
{
public:
    virtual bool operator==(Eq& operand) = 0;  // References passing doesn't slice
};

然后在 Day 中更新其覆盖:

bool operator==(Eq& operand)
{
    if (dynamic_cast<Day*>(&operand))  // check if types compatible 
        return day == dynamic_cast<Day*>(&operand)->day;
    else return false;  // else the objects are different anyway
}

终于可以在 main() 中进行测试了:

 ...
if (d1 == d2)  // check that result is as expected !
    cout << "Yes it works !";  
else cout << "Hhmmm...";