[英]How can i accsess different parts of my inherited code
Hi i have a question regarding how to access parts of inherited code. 嗨,我有一个关于如何访问继承代码部分的问题。
Say i have this WorldObject that is a base class for alot of other objects. 说我有这个WorldObject是许多其他对象的基类。 Then i have a class Chest that inherit from WorldObject and also from the abstract class OpenAble, with some methods like open and unlock.
然后,我有一个Chest类,它继承自WorldObject和抽象类OpenAble,并带有一些方法,如打开和解锁。
In my main i have a vector of WorldObjects that i iterate through with a for loop. 在我的主要语言中,我有一个WorldObjects向量,可以使用for循环进行迭代。 Now to the question, how can i check if a worldobject is also of OpenAble and how can i access the methods in OpenAble.
现在要问的问题是,如何检查worldobject是否也是OpenAble的,以及如何访问OpenAble中的方法。
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?
}
};
You could do a dynamic_cast<OpenAble>
. 您可以执行
dynamic_cast<OpenAble>
。 This will throw an error if it is the wrong type though which is relatively expensive given that it is quite likely that the object will be the wrong type. 如果类型错误,这将引发错误,但是由于对象很可能是错误的类型,所以这是相对昂贵的。
try{
OpenAble& opener = dynamic_cast<OpenAble&>(worldObj);
} catch (std::bad_cast& ex){
//not openable
}
BTW: As pointed out in the comments below, if you use a pointer to the base class in your container instead of references, then you can (and should) use the pointer version of dynamic_cast which will return a null in the case that your object is not OpenAble. 顺便说一句:正如下面的注释所指出的,如果您在容器中使用指向基类的指针而不是引用,则可以(并且应该)使用dynamic_cast的指针版本,如果您的对象使用该指针版本,则将返回null不是OpenAble。 Checking that in your case would be a lot more efficient than throwing and catching exceptions.
在您的情况下进行检查比抛出和捕获异常要有效得多。
I would recommend an entirely different approach though. 我会建议一种完全不同的方法。 Inject your base class with an "OpenPolicy".
为您的基类注入“ OpenPolicy”。
Eg 例如
class CanOpenPolicy {
public:
boolean canOpen(){ return true; };
boolean canClose(){ return true; };
boolean isOpen(){ return openState; };
void open(){ openState = OPEN; };
void close(){ openState = CLOSED; };
}
class NoOpenPolicy {
public:
boolean canOpen(){ return false; };
boolean canClose(){ return false; };
boolean isOpen(){ return CLOSED; };
void open(){ throw IllegalWorldObjectAction("OpenPolicy disallows operation"); };
void close(){ throw IllegalWorldObjectAction("OpenPolicy disallows operation"); };
}
//injection via template (no need for base "OpenPolicy" class, maybe some
// obscure error codes at compile though)
// Implicit interface based on how you use the injected policy.
template<OpenPol>
class WorldObject {
private:
// CTOR part of the injected contract so you are not tied to knowing how to
// build the policy. This is a key benefit over interface based injection.
OpenPol openPol;
...
public:
...
void open(){
if(openPol.canOpen()){
openPol.open();
}
}
...
}
That's not tested or anything. 这未经测试或任何东西。 Just to illustrate the idea.
只是为了说明这个想法。 You can add multiple policies for different possible operations and the best thing is that you won't need a lot of hierarchies.
您可以为不同的可能操作添加多个策略,最好的事情是您不需要太多的层次结构。
To use it just do something like this: 要使用它,只需执行以下操作:
std::unique_ptr<WorldObject>( new Chest() );
std::unique_ptr<WorldObject>( new Banana() );
std::unique_ptr<WorldObject>( new Chair() );
where: 哪里:
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> {
}
The most important thing, even though you may not like this, is to not throw away type information in the first place. 即使您可能不喜欢,最重要的是不要一开始就丢弃类型信息。
Collections of generic "object" is a Java'ism, it's not how to do things in C++. 通用“对象”的集合是Java主义,不是用C ++来做事。
That said, provided the statically known class is polymorphic (has at least one virtual member function), you can use dynamic_cast
or typeid
. 也就是说,如果静态已知的类是多态的(具有至少一个虚拟成员函数),则可以使用
dynamic_cast
或typeid
。 This functionality is known as RTTI , short for Run Time Type Information . 此功能称为RTTI ,是运行时类型信息的简称。 With some compilers you have to use special options to enable RTTI.
对于某些编译器,您必须使用特殊选项来启用RTTI。
Idiomatic use of dynamic_cast
: 习惯用法
dynamic_cast
:
WorldObject* p = ...;
if( auto p_openable = dynamic_cast<OpenAble*>( p ) )
{
// use p_openable
}
Note that dynamic_cast
to pointer signals failure by returning a nullpointer, while dynamic_cast
to reference signals failure by throwing an exception, since there are no nullreferences. 请注意,指向动态指针的
dynamic_cast
通过返回空指针来指示失败,而指向动态指针的dynamic_cast
通过抛出异常来指示失败,因为没有空引用。
The simple (obvious) solution is to use dynamic_cast and cast your objects to OpenAble
. 一种简单(显而易见)的解决方案是使用dynamic_cast并将您的对象转换为
OpenAble
。
The problem with "the simple (obvious) solution" is that usually, use of dynamic_cast shows a lack of flexibility in your class hierarchy and is a symptom of a design problem. “简单(显而易见)的解决方案”的问题在于,通常,dynamic_cast的使用表明您的类层次结构缺乏灵活性,这是设计问题的征兆。
I would offer the OpenAble interface as a set of behavior exposed through a handle: 我将提供OpenAble接口作为通过句柄公开的一组行为:
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();
}
};
Client code: 客户代码:
std::vector<WorldObject> objVector; //vector with several Worldobjects
for(auto &obj: objVector)
{
if(auto openerHandle = obj.GetOpener())
openerHandle->Open();
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.