[英]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;
这项工作利用您的对象结构和合法的上下转换:
您的替代词基于将自己限制为单个继承层次结构的原则。 您的班级设计完全不同。 您假设一个Ybase 是-一个 Xbase(始终):
这是否好,完全取决于您尝试表示的应用程序域。 如果实际上Ybase始终是Xbase,这将是非常合理的。
在这里,我只能引用Bjarne Stroustrup:
独立的概念应独立表示,并且仅在需要时才组合。 如果违反了该原则,则可以将不相关的概念捆绑在一起,或者创建不必要的依赖项。 无论哪种方式,您都会获得一组不太灵活的组件。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.