强制派生类而不再实现纯虚拟

时间:2014-05-21 09:14:07

标签: c++ inheritance object-design

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

#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类中定义所有这些函数?当然我可以实现只去基类的假人,但我认为这有点笨拙和不必要的开销,我希望可能有更好的解决方案。

1 个答案:

答案 0 :(得分:1)

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

通常情况下,在这种情况下,每IContainer个实例会创建两个CSVReader实例,而对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;
}