C++ 如何访问继承代码的不同部分
您好,我有一个关于如何访问部分继承代码的问题 假设我有一个WorldObject,它是许多其他对象的基类。然后我有一个类cast,它继承自WorldObject,也继承自抽象类OpenAble,使用了一些方法,如open和unlock 在我的主要部分中,我有一个WorldObjects的向量,我用for循环遍历它。现在我要问的问题是,如何检查worldobject是否也是可打开的,以及如何访问可打开中的方法C++ 如何访问继承代码的不同部分,c++,inheritance,multiple-inheritance,C++,Inheritance,Multiple Inheritance,您好,我有一个关于如何访问部分继承代码的问题 假设我有一个WorldObject,它是许多其他对象的基类。然后我有一个类cast,它继承自WorldObject,也继承自抽象类OpenAble,使用了一些方法,如open和unlock 在我的主要部分中,我有一个WorldObjects的向量,我用for循环遍历它。现在我要问的问题是,如何检查worldobject是否也是可打开的,以及如何访问可打开中的方法 class WorldObject { ... //implementation
class WorldObject
{
... //implementation
};
class OpenAble
{
public:
OpenAble(){}
virtual ~OpenAble(){}
virtual void Open() = 0;
virtual void Unlock(int k) = 0;
};
class Chest : public WorldObject, public OpenAble
{
... //implementation
};
main()
{
std::vector<WorldObject> objVector; //vector with several Worldobjects
for (int i =0; i < objVector.Size(); i++)
{
//check if a WorldObject is also of openable
//Do som actions like, open or unlock
//How?
}
};
class世界对象
{
…//实现
};
类可打开
{
公众:
可打开(){}
虚拟~OpenAble(){}
虚空打开()=0;
虚空解锁(int k)=0;
};
类箱:公共WorldObject,可公开
{
…//实现
};
main()
{
std::vector objVector;//包含多个世界对象的向量
对于(int i=0;i
您可以进行动态播放
。如果对象是错误的类型,这将抛出一个错误,尽管这是相对昂贵的,因为对象很可能是错误的类型
try{
OpenAble& opener = dynamic_cast<OpenAble&>(worldObj);
} catch (std::bad_cast& ex){
//not openable
}
试试看{
可开启和开启器=动态投影(worldObj);
}捕捉(标准:错误的施法和ex){
//无法打开
}
顺便说一句:正如下面的评论所指出的,如果您在容器中使用指向基类的指针而不是引用,那么您可以(而且应该)使用dynamic_cast的指针版本,如果您的对象不可打开,它将返回null。在您的案例中,检查这一点比抛出和捕获异常要有效得多
不过,我会推荐一种完全不同的方法。用“OpenPolicy”注入基类
例如
类策略{
公众:
布尔canOpen(){return true;};
布尔canClose(){return true;};
布尔isOpen(){return openState;};
void open(){openState=open;};
void close(){openState=CLOSED;};
}
阶级政策{
公众:
布尔canOpen(){return false;};
布尔canClose(){return false;};
布尔isOpen(){return CLOSED;};
void open(){throw IllegalWorldObjectAction(“OpenPolicy不允许操作”);};
void close(){throw IllegalWorldObjectAction(“OpenPolicy不允许操作”);};
}
//通过模板注入(不需要基本的“OpenPolicy”类,可能需要一些
//在编译时隐藏错误代码(尽管如此)
//基于如何使用注入策略的隐式接口。
模板
类世界对象{
私人:
//CTOR是注入合同的一部分,因此您不必知道如何
//构建策略。这是基于接口的注入的一个关键优势。
OpenPol OpenPol;
...
公众:
...
空开(){
if(openPol.canOpen()){
openPol.open();
}
}
...
}
那没有经过测试或其他什么。只是为了说明这个想法。您可以为不同的可能操作添加多个策略,最好的是不需要太多层次结构
要使用它,只需执行以下操作:
std::unique_ptr<WorldObject>( new Chest() );
std::unique_ptr<WorldObject>( new Banana() );
std::unique_ptr<WorldObject>( new Chair() );
std::unique_ptr(新胸部());
std::unique_ptr(新香蕉());
标准::独特的ptr(新椅子());
其中:
class Chest : public WorldObject<CanOpenPolicy> {
// Very little implementation in here.
// Most of it is handled in the base class and the injected policies :)
}
class Banana: public WorldObject<CanOpenPolicy> {
}
class Chair : public WorldObject<NoOpenPolicy> {
}
类箱:公共WorldObject{
//这里几乎没有实现。
//大部分在基类和注入的策略中处理:)
}
类:公共WorldObject{
}
班长:公共WorldObject{
}
最重要的一点是,即使您可能不喜欢这样做,首先也不要丢弃类型信息
通用的“对象”集合是Java'ISM,不是C++中如何做的事情。 也就是说,如果静态已知类是多态的(至少有一个虚拟成员函数),则可以使用
dynamic\u cast
或typeid
。此功能称为RTTI,是运行时类型信息的缩写。对于某些编译器,您必须使用特殊选项来启用RTTI
dynamic\u cast
的惯用用法:
WorldObject* p = ...;
if( auto p_openable = dynamic_cast<OpenAble*>( p ) )
{
// use p_openable
}
WorldObject*p=。。。;
if(自动p_可打开=动态p_铸造)
{
//使用p_openable
}
请注意,dynamic\u cast
to pointer通过返回空指针表示失败,而dynamic\u cast
to reference通过抛出异常表示失败,因为没有空引用。简单(明显)的解决方案是使用dynamic\u cast并将对象强制转换为可打开的OpenAble
“简单(明显)解决方案”的问题是,通常,使用dynamic_cast表明类层次结构缺乏灵活性,这是设计问题的一个症状
我将提供可打开的接口,作为通过句柄公开的一组行为:
class OpenAble { /* ... */ };
class WorldObject
{
//implementation
virtual OpenAble* GetOpener() { return nullptr; }
};
class Chest: public WorldObject {
struct ChestOpener: public OpenAble {
Chest *c;
virtual void Open() {
// do stuff with c
}
};
std::unique_ptr<OpenAble> chest_opener;
public:
virtual OpenAble* GetOpener() {
if(!chest_opener) {
chest_opener = new ChestOpener{ this };
}
return chest_opener.get();
}
};
类可打开{/*…*/};
类世界对象
{
//实施
虚拟可打开*GetOpener(){return nullptr;}
};
类别:公共世界对象{
结构ChestOpener:可公开{
胸部*c;
虚拟空打开(){
//用c做东西
}
};
std::独特的开胸器;
公众:
虚拟可打开*GetOpener(){
如果(!开胸器){
开胸器=新开胸器{this};
}
返回开胸器。获取();
}
};
客户端代码:
std::vector<WorldObject> objVector; //vector with several Worldobjects
for(auto &obj: objVector)
{
if(auto openerHandle = obj.GetOpener())
openerHandle->Open();
}
std::vector objVector//具有多个世界对象的向量
用于(自动和对象:对象向量)
{
if(auto openerHandle=obj.GetOpener())
openerHandle->Open();
}
请注意,dynamic_cast需要RTTI;另请参见和接受的答案。@Dennis,如果不是dynamic\u castOpenAble&>(…)
,则强制转换必须指向引用或指针。(一个指针转换,通过检查null来判断它是否成功,可能比本地处理的异常更好,无论是在效率还是总体外观方面。)是的,使用指针和检查会更好,但是OP使用的是引用,所以我想我应该这样做
std::vector<WorldObject> objVector; //vector with several Worldobjects
for(auto &obj: objVector)
{
if(auto openerHandle = obj.GetOpener())
openerHandle->Open();
}