【发布时间】:2015-10-08 10:25:13
【问题描述】:
如果编译器认为模板类的实例仍然是抽象的,即使要派生的类实现了这个抽象方法,我想知道这是否符合标准。
我的编译器是 Microsoft C/C++ Compiler 18.00.40629 (Visual Studio 2013)
下面的课程:
class MyClass {
virtual void Method() = 0;
};
template <typename T>
class MyClassT : public MyClass, public T {
};
class MyTemplateData {
void Method() {
}
};
MyClassT<MyTemplateData> MyInstance;
据我了解,MyClassT<MyTemplateData> 类是一个有效的实例,它实现了所有抽象方法,因为 MyClassT 派生自 MyClass 和 MyTemplateData。为了能够通过保持所需行为来编译此类,我应该进行哪些更改?
有一个解决方案,但让我解释一下为什么我不想关注:
template <typename T>
class MyClassT : public MyClass, public T {
void Method() {
T::Execute();
}
};
在上述情况下,它确实会编译,但是这会假设我的T 类总是实现Method。但是我想要的是在MyClassT 中有一个空的Method,而不是如果T 类实现了它,则应该被T::Method 覆盖。
所以下面的代码也可以编译,但是T::Method 永远不会被调用。
template <typename T>
class MyClassT : public MyClass, public T {
void Method() {
}
};
MyClass* Interface = new MyClassT<MyTemplateData>();
Interface->Method(); // <- here, MyTemplateData::Method() gets never called
是否有解决方案,或者这是编译器特定的错误?
编辑:再举一个例子,这次编译器应该确切地知道派生类实现了所需的抽象方法。
struct InterfaceA {
virtual void MethodA() = 0;
};
struct InterfaceAB : InterfaceA {
virtual void MethodB() = 0;
};
class ImplA : public virtual InterfaceA {
public:
void MethodA() {
}
};
class ImplAB : public virtual InterfaceAB, public ImplA {
void MethodB() {
}
};
编译器期望类ImplAB 实现MethodA,因为InterfaceAB 需要同时实现MethodA 和MethodB。然而,由于ImplAB 也是从ImplA 派生的,并且编译器确切地知道ImplA 实现了该接口,所以应该没有问题。
至少应该有一个关键字来提示编译器在哪里实现抽象方法,如下例所示。我看不出有任何理由至少在以任何方式使用 VTABLE 时应该避免这种情况。
class ImplABCD : public implements InterfaceABCD, public ImplA, public ImplB, public ImplC, public ImplC {
};
此implements 关键字表示来自InterfaceABCD 的所有抽象方法都将在ImplABCD 中实现或已经在其中一个继承类中实现。如果存在签名歧义,则在从具有相同基类的多个类继承时,按照 c++ 规范已经完成的处理情况。
【问题讨论】:
-
clang/gcc 也不编译这段代码。
-
将 CRTP 保留在图片中会使您的理解变得不必要地复杂化。只需考虑等效的
class X : public MyClass, public MyTemplateData { };- 希望您已经知道并接受这不是提供虚函数实现的有效方式,但如果不让我们知道,我们将拖入标准引号。 -
更一般地说,听起来您可以通过使用 SFINAE 检查
T::Execute是否存在来完全按照您的要求进行操作 - 只需 googlehas_member_function、has_member或类似名称,您应该会看到如何。 -
@TonyD 据我了解,多个继承的类可以实现/覆盖彼此的方法,我错了吗?
-
@bkausbk - 是的,你错了(对于 C++)。如果从抽象类继承,则必须实现纯虚函数。即使其他基类也实现了它。
标签: c++ templates inheritance overriding virtual-functions