C++ 实现子类扩展子接口而不覆盖已经覆盖的方法

Posted

技术标签:

【中文标题】C++ 实现子类扩展子接口而不覆盖已经覆盖的方法【英文标题】:C++ Implement subclasses that extends subInterfaces without overriding already overriden methods 【发布时间】:2014-02-19 20:06:14 【问题描述】:

我创建了在 C++ 中扩展其他接口的接口(抽象类),我尝试实现它们,但编译时出现错误。

以下是错误:

main.cpp: In function 'int main()':
main.cpp:36:38: error: cannot allocate an object of abstract type 'Subclass'
     Subclass * subObj = new Subclass();
                                      ^
Subclass.h:13:7: note:   because the following virtual functions are pure within 'Subclass':
 class Subclass : SubInterface 
       ^
SuperInterface.h:13:18: note:   virtual void SuperInterface::doSomething()
     virtual void doSomething()=0;

这是我的资料来源:

#include <iostream>

class SuperInterface 
public:
    virtual void doSomething() = 0;
protected:
    int someValue;
;

class SubInterface : public SuperInterface 
public:
    virtual void doSomethingElseThatHasNothingToDoWithTheOtherMethod() = 0;
protected:
    int anotherValue;
;

class Superclass : public SuperInterface 
public:
    Superclass() 
    virtual ~Superclass() 
    void doSomething() std::cout << "hello ***!";
;

class Subclass : public SubInterface 
public:
    Subclass() 
    virtual ~Subclass() 
    void doSomethingElseThatHasNothingToDoWithTheOtherMethod() std::cout << "goodbye ***!";

;

int main(void)

    Superclass * superObj = new Superclass();
    Subclass * subObj = new Subclass();

这就是我想要的: 我希望我的实现能够意识到,因此具有与已经覆盖的方法相同的行为(例如 subObj-&gt;doSomething() 方法无需再次实现即可工作)。谁能告诉我如果可能的话,我应该怎么做才能做到这一点?谢谢。

【问题讨论】:

只是用我的眼睛解析你的代码。看起来像 Subclass 将 doSomethingElse 声明为纯虚拟。这是一个错字,对吗? 公开派生,去掉Subclass::doSomethingElse声明中的=0,在Subclass中实现doSomething。好吧,您不必公开派生,但这可能是您想要的。默认情况下,类是私有继承的。我将结构用于纯接口。 这是一个错字,我的错,我重命名了另一种方法,以明确两种方法具有不同的行为。 @codah 当你说在子类中实现 doSomething 时,你是在要求我做我不想做的事情。我正在寻找一种替代方法,它不需要进一步实现方法。而且我也不想在 SubInterface 中实现它,因为我想保持接口和实现分离并且实现中的继承始终存在 好吧对不起,我误会了;收回。 【参考方案1】:

不,你不能通过简单的继承来做你想做的事。 Subclass 绝不会继承或提供doSomething() 的实现,因此您不能随意调用subObj-&gt;doSomething()。你必须遵守subInterface的接口契约。

您可以从SuperclassSubinterface 继承Subclass,并将doSomething() 实现为一种代理Superclass::doSomething()。您仍然需要一个实现,但您不必“重新实现”它。

【讨论】:

【参考方案2】:

您收到错误是因为您正在尝试创建抽象类的对象。 由于这条线void doSomethingElse()=0;,您的Subclass 是一个抽象类。 如果一个类有一个纯虚函数,那么它将是一个抽象类。不能创建抽象类的对象,只能有引用或指向它的指针。

为了摆脱错误,doSomethingElseSubclass 中的声明应该是

void doSomethingElse();

而不是void doSomethingElse()=0;

我也不明白为什么需要两个接口。您可以从SuperInterface 派生Subclass,因为它与SubInterface 基本相同

【讨论】:

doSomethingElse() 重命名以明确 doSomething() 和 doSomethingElse() 完全没有共同点,我也可能有完全不同的行为和返回类型。 =0 是一个错字现已更正!【参考方案3】:

说实话,我完全确定你的设计想要表达什么,但这里至少有两个技术错误:

1.) 您在所有情况下都使用 private 继承,因此您实际上根本不处理“接口”。公共继承是这样实现的:

class SubInterface : public SuperInterface

2.) 您将=0 用于您显然想要实现的功能。

这将修复编译器错误,但设计仍然存在问题。考虑到您在问题末尾给出的动机,我建议组合而不是(公共)继承。在 C++ 中,共享功能最好用组合来表达。简单来说,就是将常用的功能封装在一个单独的类中,并为其他类配备它的对象。

class CommonFunctionality

//...
public:
    void doSomething();
    void doSomethingElse();
;

class SuperClass

//...
private:
    CommonFunctionality m_functionality;
;

class SubClass : public SuperClass

//...
private:
    CommonFunctionality m_functionality;
;

事实上,也许您甚至需要为 CommonFunctionality 创建一个类。也许简单的独立函数就可以了。具有 Java 背景的程序员(并且您的代码看起来有点像)倾向于将过多的东西放入类中,而不是 C++ 中所必需的。

【讨论】:

这是一个错字,我的错,我重命名了另一种方法,以明确两种方法具有不同的行为。顺便说一下,在继承声明中添加“public”并不会改变错误【参考方案4】:

您的“子类”类应覆盖 2 个纯虚方法,因此:

class Subclass : SubInterface 
public:
    Subclass();
    virtual ~Subclass();
    void doSomethingElse() override;
    void doSomething() override;
;

不这样做或声明

void doSomethingElse()=0;

class 子类也变成抽象的,不能被实例化。你可以看看:http://www.parashift.com/c++-faq-lite/pure-virtual-fns.html

这就是我想要的:我希望我的实现能够被意识到 与已经覆盖的方法相同的行为(例如 subObj->doSomething() 方法无需实现即可工作 再次)。谁能告诉我我应该怎么做才能做到这一点,如果 甚至有可能!???谢谢。

--> 可能声明方法是虚拟的而不是纯虚拟的

【讨论】:

可以在方法声明中添加“覆盖”。 我知道为什么子类也变得抽象了,我的问题是:有没有办法,一种解决方法,不必再次覆盖已经覆盖的方法。【参考方案5】:

有2个问题,编译器明确说明:

问题 1

Subclass 中的SubInterface::doSomethingElse()() 被声明为纯虚拟,不管您试图在源文件中定义它(我很确定,这是一种复制粘贴错误)。


class Subclass : SubInterface

public:
    Subclass();
    virtual ~Subclass();
    void doSomethingElse() = 0; // still pure? 
;

解决办法很明显:


class Subclass : SubInterface

public:
    Subclass();
    virtual ~Subclass();
    virtual void doSomethingElse() override 
       
    

;

(此处使用 C++11 override 说明符,因此编译器将检查覆盖的正确性;这不是强制性的)

问题 2

doSomething() 甚至没有被覆盖,SuperInterfaceSubclass 都没有,所以它保持纯虚拟。尽管doSomething()Superclass 中被覆盖,但Subclass 不知道Superclass 的存在。

解决方案:在SuperInterfaceSubclassSubclass 的任何子代中覆盖doSomething()(还没有)。例如覆盖Subclass:


class Subclass : SubInterface

public:
    Subclass();
    virtual ~Subclass();
    virtual void doSomething() override 
       
    

    virtual void doSomethingElse() override 
       
    

;

其他问题:

您在没有可见性说明符的情况下继承,即privately。使用public继承,直到你真的需要别的东西:

class Derved : public Base ;

您的源文件具有 .c 扩展名,但包含 C++ 代码。如果您没有通过命令行参数显式声明编程语言,这可能会使一些编译器感到困惑。按照惯例,大多数程序员使用.cpp 扩展名,而大多数编译器将此类文件视为 C++ 源文件。

【讨论】:

更正我的代码。事实是我无意中删除了部分代码。我还做了一些修改,以使我希望更清楚的整个事情! @PaikuHan BTW,不建议您编辑您的第一个帖子修复问题。这给以后会阅读此主题的任何人增加了困惑。 .c 扩展名是一个错字,因为您可能已经注意到阅读错误代码,该代码给出了带有 cpp 扩展名的文件名。我的 IDE 无法识别覆盖说明符,并且在编译时出现错误,指出如您所说,它仅适用于 c++11。但是我对您的解决方案的最大问题是,即使您在超类中覆盖了 doSomething(),您仍然必须在子接口或子类中再次覆盖它。现在我想真正的问题是:真的没有其他方法可以做到...子类的多重继承可能??? 我知道肯定会有混乱,但唯一的其他解决方案是删除整个帖子并重新写一遍

以上是关于C++ 实现子类扩展子接口而不覆盖已经覆盖的方法的主要内容,如果未能解决你的问题,请参考以下文章

C ++如何避免从接口覆盖虚拟方法

Java:子类实现接口,但父类覆盖接口的成员?

在 Swift 3.1 中为 UIView 子类设置默认外观而不覆盖 initialize()

方法重载(overroad)和方法覆盖(override)------java基础知识总结

Weka java扩展子样本过滤器

C++ 纯虚函数 虚函数 override