覆盖 return 基本类型的函数
Override function that return base type
我有两个 class。基础 class Parent
和派生 class Child
。 Class Parent
具有 returns 其 class 类型的纯虚函数。如何在派生 class?
中覆盖它
class Parent
{
public:
virtual Parent* OverrideMe(Parent* func) = 0;
};
class Child : public Parent
{
public:
Child* OverrideMe(Child* func) override;
};
我尝试了 Child* OverrideMe(Child* func) override;
但我最终遇到错误,它没有覆盖基础 class 成员。
函数参数的类型和函数的 cv 限定符必须相同。所以你可以使用
Child* OverrideMe(Parent* func) override;
你没有在这里重写,因为你的 OverrideMe
函数没有接受与你试图重写的基础 class 中的函数相同的参数:
class Parent
{
public:
virtual Parent* OverrideMe(Parent* func) = 0;
};
class Child : public Parent
{
public:
virtual Child* OverrideMe(Parent* func) override;
};
这个"smells bad",也就是说,你是"breaking"正常的"any object should be replaceable with any other object that is derived from it"。
如果您在 base-class 中有一个接口函数,那么该函数在整个 class 层次结构中应该采用相同的类型。
所以正确的做法是:
Parent* OverrideMe(Parent* func)覆盖;
(正如 juanchopanza 所说,您可以 return 派生类型,但您确定父 returned 值将始终相同 class 吗?对我来说,这看起来像是可能 return "any derived object" 的函数类型,在这种情况下,您要么撒谎,要么最终得到 "Interesting effects")
如果出于某种原因,这实际上 "work" 您的情况,那么您可能不应该以这种方式使用继承。
如果 C++ 具有完整的协变和逆变支持,正确的关系将是 逆变 输入和 协变 输出。即:
struct Organism { };
struct Animal : Organism {
virtual Animal* OverrideMe(Animal* ) = 0;
};
struct Dog : Aniaml {
Dog* OverrideMe(Organism* ) override { ... }
↑↑↑ ↑↑↑↑↑↑↑↑
covariant contravariant
};
看起来有点不直观,但确实有道理。如果您期望 Animal*
,您应该能够处理任何 Animal*
(其中 Dog*
符合条件)。相反,如果您在 Animal*
上执行某些操作,您只需要一个可以采用 Animal*
的操作 - 并且采用 Organism*
的操作符合该条件。
请注意,如果输入是 co 变体,那将破坏类型系统。考虑类似的东西;
Animal* a = new Dog;
a->OverrideMe(new Cat);
如果允许 Dog::OverrideMe
获得 Dog*
,那将失败 - Cat*
不是 Dog*
!所以允许使用 Animal*
... 或任何比它更通用的东西(例如 Organism*
),因为所有这些都可以正常工作。
C++ 不 在输入中支持逆变,在输出中只支持 协方差。所以你可以这样写:
Dog* OverrideMe(Animal* ) override { ... }
或:
Animal* OverrideMe(Animal* ) override { .... }
但没有别的。
我有两个 class。基础 class Parent
和派生 class Child
。 Class Parent
具有 returns 其 class 类型的纯虚函数。如何在派生 class?
class Parent
{
public:
virtual Parent* OverrideMe(Parent* func) = 0;
};
class Child : public Parent
{
public:
Child* OverrideMe(Child* func) override;
};
我尝试了 Child* OverrideMe(Child* func) override;
但我最终遇到错误,它没有覆盖基础 class 成员。
函数参数的类型和函数的 cv 限定符必须相同。所以你可以使用
Child* OverrideMe(Parent* func) override;
你没有在这里重写,因为你的 OverrideMe
函数没有接受与你试图重写的基础 class 中的函数相同的参数:
class Parent
{
public:
virtual Parent* OverrideMe(Parent* func) = 0;
};
class Child : public Parent
{
public:
virtual Child* OverrideMe(Parent* func) override;
};
这个"smells bad",也就是说,你是"breaking"正常的"any object should be replaceable with any other object that is derived from it"。
如果您在 base-class 中有一个接口函数,那么该函数在整个 class 层次结构中应该采用相同的类型。
所以正确的做法是:
Parent* OverrideMe(Parent* func)覆盖;
(正如 juanchopanza 所说,您可以 return 派生类型,但您确定父 returned 值将始终相同 class 吗?对我来说,这看起来像是可能 return "any derived object" 的函数类型,在这种情况下,您要么撒谎,要么最终得到 "Interesting effects")
如果出于某种原因,这实际上 "work" 您的情况,那么您可能不应该以这种方式使用继承。
如果 C++ 具有完整的协变和逆变支持,正确的关系将是 逆变 输入和 协变 输出。即:
struct Organism { };
struct Animal : Organism {
virtual Animal* OverrideMe(Animal* ) = 0;
};
struct Dog : Aniaml {
Dog* OverrideMe(Organism* ) override { ... }
↑↑↑ ↑↑↑↑↑↑↑↑
covariant contravariant
};
看起来有点不直观,但确实有道理。如果您期望 Animal*
,您应该能够处理任何 Animal*
(其中 Dog*
符合条件)。相反,如果您在 Animal*
上执行某些操作,您只需要一个可以采用 Animal*
的操作 - 并且采用 Organism*
的操作符合该条件。
请注意,如果输入是 co 变体,那将破坏类型系统。考虑类似的东西;
Animal* a = new Dog;
a->OverrideMe(new Cat);
如果允许 Dog::OverrideMe
获得 Dog*
,那将失败 - Cat*
不是 Dog*
!所以允许使用 Animal*
... 或任何比它更通用的东西(例如 Organism*
),因为所有这些都可以正常工作。
C++ 不 在输入中支持逆变,在输出中只支持 协方差。所以你可以这样写:
Dog* OverrideMe(Animal* ) override { ... }
或:
Animal* OverrideMe(Animal* ) override { .... }
但没有别的。