我正在和朋友一起开发一个GUI库,我们遇到了如何确定某个元素是否应该可点击的问题(或者是可移动的,等等)。
我们决定只检查特定对象是否存在函数,所有gui元素都存储在带有指向基类的指针的向量中。
例如,如果我有
class Base {};
class Derived : public Base
{
void example() {}
}
vector<Base*> objects;
如何检查对象成员是否具有名为example的函数。
如果这不可能实现可选行为(例如点击等)的不同方式。
答案 0 :(得分:8)
您可以在基类中使用虚拟IsClickable()
方法:
class Widget {
public:
virtual bool IsClickable(void) { return false; }
};
class ClickableWidget : public Widget
{
public:
virtual bool IsClickable(void) { return true; }
}
class SometimesClickableWidget : public Widget
{
public:
virtual bool IsClickable(void);
// More complex logic punted to .cc file.
}
vector<Base*> objects;
这样,对象默认不可点击。可点击对象可以覆盖IsClickable()
或子类ClickableWidget
而不是Widget
。不需要花哨的元编程。
编辑:确定某些内容是否可点击:
if(object->IsClickable()) {
// Hey, it's clickable!
}
答案 1 :(得分:4)
最好的方法是使用mixin多重继承,a.k.a。接口。
class HasExample // note no superclass here!
{
virtual void example() = 0;
};
class Derived : public Base, public HasExample
{
void example()
{
printf("example!\n");
}
}
vector<Base*> objects;
objects.push_back(new Derived());
Base* p = objects[0];
HasExample* he = dynamic_cast<HasExample*>(p);
if (he)
he->example();
dynamic_class&lt;&gt;()在运行时测试给定对象是否实现HasExample,并返回HasExample *或NULL。但是,如果您发现自己使用的是HasExample *,那么通常需要重新考虑您的设计。
小心!当像这样使用多重继承时,那么(HasExample *)ptr!= ptr。将指针强制转换为其父项之一可能会导致指针的值发生变化。这是完全正常的,在方法内部,这将是您所期望的,但如果您不了解它,它可能会导致问题。
编辑:添加了dynamic_cast&lt;&gt;()的示例,因为语法很奇怪。
答案 2 :(得分:1)
我会创建一个接口,使方法成为接口的一部分,然后在任何应该具有该功能的类上实现该接口。
在尝试确定Object是否实现某些功能集(而不是检查方法名称)时,这将是最有意义的:
class IMoveable
{
public:
virtual ~IMoveable() {}
virtual void Move() = 0;
};
class Base {};
class Derived : public Base, public IMoveable
{
public:
virtual void Move()
{
// Implementation
}
}
现在您不再检查方法名称,而是转换为IMoveable类型并调用Move()。
答案 3 :(得分:1)
如果您愿意使用RTTI。 。
您应该创建Clickable
,Movable
等类,而不是检查类名。然后,您可以使用dynamic_cast
查看各种元素是否实现了您感兴趣的界面。
IBM有一个简短的示例程序,用于说明dynamic_cast here。
答案 4 :(得分:0)
我不确定通过反思做到这一点很容易或很好。我认为更好的方法是拥有一个具有GUIElement
功能的接口(类似于isClickable
)。使您的元素实现接口,然后可点击的元素将在函数的实现中返回true
。所有其他人当然会回归虚假。当您想知道某些内容是否可点击时,只需将其命名为isClickable
即可。这样,您可以在运行时将元素从可点击变为不可点击 - 如果在您的上下文中有意义的话。