c ++库:应用程序在继承层次结构中插入一个类

时间:2015-03-18 04:06:41

标签: c++ templates inheritance multiple-inheritance

我有一个具有以下继承层次结构的库(模型):

struct Xbase {
    virtual void f() = 0;
};

struct Derived1 : public Xbase {
    void f() { std::cerr << "Derived1::f\n"; }
};

struct Derived2 : public Xbase {
    void f() { std::cerr << "Derived2::f\n"; }
};
struct Storage {
    std::map<int, Xbase*> data;
    Xbase* get(int i) {
        auto it = data.find(i);
        return (it == data.end() ) ? nullptr : it->second;
    }
};

库跟踪指向基本结构的指针,并允许在这个小例子中通过整数id检索它们。有一个应用程序使用该库,并希望通过引入第二个基类Ybase来提供一些功能:

struct Ybase {
    virtual void g() { std::cerr << "Ybase::g\n"; }
};

struct AppDerived1 : public Derived1, public Ybase {
    void f() { std::cerr << "AppDerived1::f\n"; }
};

struct AppDerived2 : public Derived2, public Ybase {
    void f() { std::cerr << "AppDerived2::f\n"; }
};

当然比如

int i = 5;
Storage storage;
Xbase* xbase = storage.get(i);
Ybase* ybase = static_cast<Ybase *>(xbase);

效果不好

$ g++ -std=c++11 t.cpp
t.cpp: In function ‘int main()’:
t.cpp:21:45: error: invalid static_cast from type ‘Xbase*’ to type ‘Ybase*’

我想提供派生类的模板版本,以便app开发人员可以将他的类插入到库层次结构中。

库:

template<typename T>
struct Derived1 : public T {
    void f() { std::cerr << "Derived1::f\n"; }
};

应用程序所有者:

struct Ybase : public Xbase {
    virtual void g() { std::cerr << "Ybase::g\n"; }
};

struct AppDerived1 : public Derived1<Ybase> {
    ...
};
/* same for AppDerived2 */
Xbase* xbase = storage.get(i);
Ybase* ybase = static_cast<Ybase *>(xbase);
ybase->g();

这会创建一个单独的继承行,并且强制转换应该有效。

我想了解这是一个好主意还是一个坏主意,以及可能的替代方案。请注意,我确实需要层次结构中的公共基类Xbase,因为我必须能够从名称和ID等外部数据中检索基类指针。应用程序开发人员的问题是应用程序还需要其基本指针,因为应用程序不知道它接收的对象(AppDerived1或2)的类型。谢谢你的阅读。

1 个答案:

答案 0 :(得分:1)

初步评论:

您无法将Xbase*转换为Ybase*,因为这些是不相关的类 但是,由于多重继承和动态转换,如果您知道可以使用的派生类最多,则可以安全地从Xbase转换为Ybase:

Ybase* ybase{};
Derived1 *pd1 = dynamic_cast<Derived1*>(xbase);   // is it a Derived 1 ?  
if (pd1) {                                        // if yes
    AppDerived1 *app = dynamic_cast<AppDerived1*>(pd1); // Then look for an AppDerived 1
    if (app)                                      // If valid cast
        ybase = app;                              // we can cass the AppDerived1 to an Ybase
}
else {                                           // same approach for the second type 
    Derived2 *pd2 = dynamic_cast<Derived2*>(xbase);   // is it a Derived 2 ?  
    if (pd2) {                                        // if yes
        AppDerived2 *app = dynamic_cast<AppDerived2*>(pd2);
        if (app)
            ybase = app;
    }
}  // if ybase is still nullptr here, it means that we couldn't find a valid conversion path
cout << (ybase ? "Success " : "Fail ") << (void*)ybase << endl; 

这可以利用您的对象结构和合法的上下铸件:
AppDerived1-structure

评估您的替代方案:

您的alernative是建立在将自己限制在单个继承层次结构的原则之上的。你班级的设计完全不同。您假设Ybase 是-a Xbase(始终):

Single-inheritance-alternative

这是否好是完全取决于您尝试表示的应用程序域。如果实际上Ybase总是一个Xbase,这将是完美的意义。

这里我只能引用Bjarne Stroustrup:

  

独立概念应该独立代表,应该是   仅在需要时合并。在违反这一原则的地方,你   要么将不相关的概念捆绑在一起,要么创造不必要   依赖。无论哪种方式,您都可以获得灵活性较低的组件集。