c++ - 强制派生类而不再次实现纯虚拟

标签 c++ inheritance object-design

我定义了一个接口(interface)类A其中定义了一些基本功能。在我的实现中,我有一个基类 A0它实现了这个接口(interface),并从这个基类派生了层次结构中的其他几个类。

#include <iostream>
#include <string>

class IContainer
{
public:
    IContainer() {};
    virtual ~IContainer() {};

    virtual void loadDefaults() = 0;
    virtual void storeDefaults() = 0;

    virtual bool open() = 0;
    virtual bool close() = 0;
};

class IContainerReader
{
public:
    IContainerReader() {};
    virtual ~IContainerReader() {};

    virtual bool read() = 0;
};

class IContainerWriter
{
public:
    IContainerWriter() {};
    virtual ~IContainerWriter() {};

    virtual bool write() = 0;
};

class ContainerBase : public IContainer
{
public:
    ContainerBase() {}
    virtual ~ContainerBase() {}

    void loadDefaults() {}
    void storeDefaults() {}
};

class CSVBase : public ContainerBase
{
public:
    CSVBase() {}
    virtual ~CSVBase() {}

    void setFilename() {}
    bool open() { return true; }
    bool close() { return true; }
};


class CSVReader : public CSVBase, public IContainerReader
{
public:
    CSVReader() {}
    virtual ~CSVReader() {}

    bool read() { return true; }
};

class CSVWriter : public CSVBase, public IContainerWriter
{
public:
    CSVWriter() {}
    virtual ~CSVWriter() {}

    bool write() { return true; }
};

int main(int argc, char *argv[])
{
    CSVReader r;
    CSVWriter w;
    IContainerReader *ir = &r;
    IContainerWriter *iw = &w;

    ir->open();
    iw->open();

    ir->read();
    iw->write();

    ir->close();
    iw->close();

    return 0;
}

如你所见,我定义了一个 IContainerReader和一个 IContainerWriter定义仅与各自实现相关的特殊功能的类。

但现在我遇到了一个问题,因为我想确保 Reader 或 writer 也始终拥有容器基础。所以合乎逻辑的解决方案是导出 IContainerReader/-Writer来自 IContainer .但是当我这样做时,thge 编译器会提示,因为它现在期望 Reader/Writer对象也再次实现基类函数,这些函数已经通过基类定义。但是如果我让IContainerReader不是来自 IContainer指向这些对象之一的指针不保证具有 IContainer功能也是如此。

如果我尝试像这样编译它,我会出错,因为 IContainerReader不是 IContainer

||=== Build: Debug in CPPMingW (compiler: GNU GCC Compiler) ===|
D:\src\c\Tests\CPPMingW\main.cpp||In function 'int main(int, char**)':|
D:\src\c\Tests\CPPMingW\main.cpp|83|error: 'class IContainerReader' has no member named 'open'|
D:\src\c\Tests\CPPMingW\main.cpp|84|error: 'class IContainerWriter' has no member named 'open'|
D:\src\c\Tests\CPPMingW\main.cpp|89|error: 'class IContainerReader' has no member named 'close'|
D:\src\c\Tests\CPPMingW\main.cpp|90|error: 'class IContainerWriter' has no member named 'close'|
||=== Build failed: 4 error(s), 0 warning(s) (0 minute(s), 5 second(s)) ===|

但是,如果我导出 IContainerReader来自 IContainer应该是,我收到以下错误:

||=== Build: Debug in CPPMingW (compiler: GNU GCC Compiler) ===|
D:\src\c\Tests\CPPMingW\main.cpp||In function 'int main(int, char**)':|
D:\src\c\Tests\CPPMingW\main.cpp|78|error: cannot declare variable 'r' to be of abstract type 'CSVReader'|
D:\src\c\Tests\CPPMingW\main.cpp|58|note:   because the following virtual functions are pure within 'CSVReader':|
D:\src\c\Tests\CPPMingW\main.cpp|11|note:     virtual void IContainer::loadDefaults()|
D:\src\c\Tests\CPPMingW\main.cpp|12|note:     virtual void IContainer::storeDefaults()|
D:\src\c\Tests\CPPMingW\main.cpp|14|note:     virtual bool IContainer::open()|
D:\src\c\Tests\CPPMingW\main.cpp|15|note:     virtual bool IContainer::close()|
D:\src\c\Tests\CPPMingW\main.cpp|79|error: cannot declare variable 'w' to be of abstract type 'CSVWriter'|
D:\src\c\Tests\CPPMingW\main.cpp|67|note:   because the following virtual functions are pure within 'CSVWriter':|
D:\src\c\Tests\CPPMingW\main.cpp|11|note:     virtual void IContainer::loadDefaults()|
D:\src\c\Tests\CPPMingW\main.cpp|12|note:     virtual void IContainer::storeDefaults()|
D:\src\c\Tests\CPPMingW\main.cpp|14|note:     virtual bool IContainer::open()|
D:\src\c\Tests\CPPMingW\main.cpp|15|note:     virtual bool IContainer::close()|
||=== Build failed: 2 error(s), 0 warning(s) (0 minute(s), 6 second(s)) ===|

因此编译器希望我在派生类中重新实现基类中的所有函数。

那么有没有办法解决这个问题,而不必在 Reader/Writer 类中再次定义所有这些函数?当然,我可以实现直接下到基类的虚拟对象,但我认为这有点笨拙且不必要的开销,我希望对此有更好的解决方案。

最佳答案

希望我做对了。你有一种菱形继承(钻石问题)。您通过两条路径从 IContainer 继承。

通常在这种情况下,您会为每个 CSVReader 实例创建两个 IContainer 实例,并且对 IContainer 方法的调用将是模糊的。在您的情况下,通过 IContainerReader 的路径没有定义上述函数。 Virtual inheritance使得只创建一个实例。

IContainer 的继承应声明为virtualVirtual inheritance使得来自类的每个派生“都将组合在一起”(抱歉,不是很专业的术语,但这是我用简单英语理解的方式)。在您的情况下,只会为两个路径创建一个 IContainer 拷贝,并且 vtable 将从两个路径填充。

此代码编译:

#include <iostream>
#include <string>

class IContainer
{
public:
    IContainer() {};
    virtual ~IContainer() {};

    virtual void loadDefaults() = 0;
    virtual void storeDefaults() = 0;

    virtual bool open() = 0;
    virtual bool close() = 0;
};

class IContainerReader : virtual public IContainer
{
public:
    IContainerReader() {};
    virtual ~IContainerReader() {};

    virtual bool read() = 0;
};

class IContainerWriter : virtual public IContainer
{
public:
    IContainerWriter() {};
    virtual ~IContainerWriter() {};

    virtual bool write() = 0;
};

class ContainerBase : virtual public IContainer
{
public:
    ContainerBase() {}
    virtual ~ContainerBase() {}

    void loadDefaults() {}
    void storeDefaults() {}
};

class CSVBase : public ContainerBase
{
public:
    CSVBase() {}
    virtual ~CSVBase() {}

    void setFilename() {}
    bool open() { return true; }
    bool close() { return true; }
};


class CSVReader : public CSVBase, public IContainerReader
{
public:
    CSVReader() {}
    virtual ~CSVReader() {}

    bool read() { return true; }
};

class CSVWriter : public CSVBase, public IContainerWriter
{
public:
    CSVWriter() {}
    virtual ~CSVWriter() {}

    bool write() { return true; }
};

int main(int argc, char *argv[])
{
    CSVReader r;
    CSVWriter w;
    IContainerReader *ir = &r;
    IContainerWriter *iw = &w;

    ir->open();
    iw->open();

    ir->read();
    iw->write();

    ir->close();
    iw->close();

    return 0;
}

关于c++ - 强制派生类而不再次实现纯虚拟,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23778869/

相关文章:

c++ - 分形编程 - 有什么方法可以优化此代码以进行实时渲染?

c++ - C++ 的 GeoIP 有这个库吗?

oop - 如何在复杂的纸牌游戏中平衡多态/继承/TypeData架构与原型(prototype)/享元模式的技巧?

具有通用结构的 C# 类设计

c++ - 丰富的数字测试

c++ - 抽象类和继承的问题

ios - XcCode5 : How do relationships work with interface builder?

c++ - 在没有 boost 和 c++0x 的情况下安全地进行类型删除

c++ - std::mutex 与 std::recursive_mutex 作为类成员

python - Python 中的@property 速度开销