繁体   English   中英

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

[英]c++ library: application inserts a class in inheritance hierarchy

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

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*’

我想到了提供派生类的模板版本,以便应用程序开发人员可以将其类插入库层次结构中。

图书馆:

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)。 谢谢阅读。

初步说明:

您不能将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结构

评估您的替代方案:

您的替代词基于将自己限制为单个继承层次结构的原则。 您的班级设计完全不同。 您假设一个Ybase 是-一个 Xbase(始终):

单继承的替代方案

这是否好,完全取决于您尝试表示的应用程序域。 如果实际上Ybase始终是Xbase,这将是非常合理的。

在这里,我只能引用Bjarne Stroustrup:

独立的概念应独立表示,并且仅在需要时才组合。 如果违反了该原则,则可以将不相关的概念捆绑在一起,或者创建不必要的依赖项。 无论哪种方式,您都会获得一组不太灵活的组件。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM