我知道这个问题有点宽泛和不精确,但这就是我想要的:
struct DynTyped { /* HOW? */ };
class Animal : public DynTyped {};
class Dog : public Animal {};
class Cat : public Animal {};
// expect to work
Animal* a1 = new Dog;
Dog* d1 = DOWNCAST<Dog*>(a1);
d1->hello();
// expect to throw
Animal* a2 = new Cat;
Dog* d2 = DOWNCAST<Dog*>(a2);
d2->hello();
我能做到的一种方法是在基类中设置一个字段。
class Animal {
enum AnimalType { Dog, Cat };
protected:
AnimalType type_;
}
但是我想要一种方法在更高的基类中实现它,因为我可能有一个形状基类,我不想再做那种类型的字段技巧。
答案 0 :(得分:0)
这不是一个完美的替代品,但是,CRTP有你想要的潜力...
顺便说一下,你为什么要避免使用RTTI?无法模拟RTTI。答案 1 :(得分:0)
这可能看似微不足道,但你可以这样做:
class Dog;
class Cat;
struct DynTyped { virtual Dog*AsDog() {return 0;} virtual Cat*AsCat() {return 0;};
class Animal : public DynTyped {};
class Dog : public Animal {virtual Dog*AsDog() {return this;};};
class Cat : public Animal {virtual Cat*AsCat() {return this;};}
答案 2 :(得分:0)
首先,您需要向基类添加一个虚函数,该函数将在运行时识别对象的实际类型。然后,您可以创建一个封装实际类型转换的模板包装函数。
我的意思是:
class Animal {
public:
virtual int get_Type() const = 0;
};
class Dog : public Animal {
public:
static const int s_Type = 1;
virtual int get_Type() const { return s_Type; }
};
class Cat : public Animal {
public:
static const int s_Type = 2;
virtual int get_Type() const { return s_Type; }
};
template <class T>
T* DynamicCast(Animal* p)
{
return (T::s_Type == p->get_Type()) ? static_cast<T*>(p) : NULL;
}
这是个主意。您可以使用任何类型来发现实际的对象类型,在此示例中我使用了int
,您可以为此创建enum
。
另请注意,这适用于类型匹配的情况,相反,如果目标类型是继承的,则RTTI也可以工作,即源对象可以是派生类型。 这是因为RTTI信息更复杂,它包含整个层次结构。
答案 3 :(得分:0)
一种方法是使用虚拟函数进行投射。你可以这样做:
#include <exception>
class Animal;
class Dog;
class Cat;
struct InvalidConversion : public std::exception
{
};
struct DynTyped {
virtual Animal *IsAnimal() { throw InvalidConversion(); }
virtual Dog *IsDog() { throw InvalidConversion(); }
virtual Cat *IsCat() { throw InvalidConversion(); }
};
class Animal : public DynTyped
{
virtual Animal *IsAnimal() override { return this; }
};
class Dog : public Animal
{
virtual Dog *IsDog() override { return this; }
};
class Cat : public Animal
{
virtual Cat *IsCat() override { return this; }
};
然后使用它:
// expect to work
Animal* a1 = new Dog;
Dog* d1 = a1->IsDog();
d1->hello();
// expect to throw
Animal* a2 = new Cat;
Dog* d2 = a2->IsDog();
d2->hello();