在设计中避免RTTI

Pau*_*ulH 1 c++ data-structures

我有一个Visual Studio 2008 C++应用程序,它有几种类型的对象,它们来自一个共同的基础.例如:

class Base
{
public:
    std::string Time() const { /*return formatted time*/; };
private:
    SYSTEMTIME time_;
};

class Foo : public Base
{
public:
    const char* FooFunc() const { return "Hello from foo!"; };
};

typedef std::vector< Base > BaseList;

class Bar : public Base
{
public:
    const char* BarFunc() const { return "Hello from bar!"; };

    void push_back( const Base& obj ) { list_.push_back( obj ); };
    BaseList::const_iterator begin() const { return list_.begin(); };
    BaseList::const_iterator end() const { return list_.end(); };

private:
    BaseList list_;
};
Run Code Online (Sandbox Code Playgroud)

这些对象存储在一个std::vector< Base >.我需要输出每个FooBar类中的信息以及存储在基础中的信息.但是,我想避免RTTI.

int main( int, char** )
{
    BaseList list;

    Foo foo;
    Bar bar;
    Foo foo2;

    list.push_back( foo );
    list.push_back( bar );
    bar.push_back( foo2 );

    for( BaseList::const_iterator it = list.begin();
         it != list.end();
         ++it )
    {
        printf( "%s ", it->Time() );

        // print Foo information for objects of type Foo
        // OR print Bar information for objects of type Bar.
        // Descend in to objects of type Bar to print its children.
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,所需的输出将是:

11:13:05 Hello from foo!
11:22:14 Hello from bar!
    11:26:04 Hello from foo!
Run Code Online (Sandbox Code Playgroud)

我可以对此设计做出哪些更改,以避免使用RTTI作为解决方案但仍允许我在嵌套的树状结构中存储类似FooBar具有不同功能的对象?

谢谢,PaulH

Ste*_*end 14

这是通过继承的vanilla运行时多态性.

替换FooFuncBarFunc用纯虚拟方法的实现DoTheOutput从继承Base,然后通过调用该方法Base*的循环.如果您需要Base输出过那么Base::DoTheOutput就不会是纯粹的,并会由子类实现被调用,他们已经完成了派生类特定的输出之后.

如果你需要保持BarFuncFooFunc完整的接口,你可以让他们委托给新的DoTheOutput功能.


Syl*_*sne 10

首先,Bar类存在问题.由于你正在使用a std::vector< Base >,你的对象被切片(这是对象的Base部分的副本插入到向量中,而不是你的对象).你会想要使用a std::vector< Base* >,这是一个指针向量.

其次,要做你想做的事,你可以在Foo和Bar类中使用Base类重写的虚方法.如果您认为您的应用程序需要多个遍历操作,您可以查看访问者模式.


Fre*_*son 6

Ok, at Alf's suggestion, I'm making my comment into an answer.

甚至RTTI也不会在这里工作,因为你Base在向量中存储对象.对象将被切片,从派生类中丢失任何信息.你需要存储Base指针,最好是智能指针.此外,您没有虚拟功能.RTTI至少需要一个虚拟功能才能工作.

使您的函数成为纯虚方法Base,然后使用适当的行为在每个派生类中覆盖它.这将构成Base一个抽象类,使得切片问题变得不可能.