如何在没有RTTI的情况下设计动态类型系统?

时间:2017-11-28 12:22:22

标签: c++ types casting rtti

我知道这个问题有点宽泛和不精确,但这就是我想要的:

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_;
}

但是我想要一种方法在更高的基类中实现它,因为我可能有一个形状基类,我不想再做那种类型的字段技巧。

4 个答案:

答案 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();