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++ 工作方式的关键点。
- 要进行虚拟覆盖,您必须具有相同的方法签名。
- 为避免切片,您需要发送引用或指针,而不是堆栈上的对象。
- 最后,发送值可能会占用大量内存(与引用或指针相比)。
这里有几个我发现的关于在处理继承时如何进行 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 Day
与 Eq
的签名不匹配,因此无法使用。
- 您按值传递运算符的操作数。这意味着将有 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...";
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++ 工作方式的关键点。
- 要进行虚拟覆盖,您必须具有相同的方法签名。
- 为避免切片,您需要发送引用或指针,而不是堆栈上的对象。
- 最后,发送值可能会占用大量内存(与引用或指针相比)。
这里有几个我发现的关于在处理继承时如何进行 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==
的 签名 forDay
与Eq
的签名不匹配,因此无法使用。- 您按值传递运算符的操作数。这意味着将有 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...";