[英]Avoiding RTTI in a design
我有一個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_;
};
這些對象存儲在std::vector< Base >
。 我需要輸出每個Foo
和Bar
類中的信息以及存儲在基礎中的信息。 但是,我想避免使用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;
}
在這種情況下,所需的輸出將是:
11:13:05 Hello from foo!
11:22:14 Hello from bar!
11:26:04 Hello from foo!
我可以對此設計進行哪些更改,從而避免使用RTTI作為解決方案,但仍然允許我將具有不同功能的對象(如Foo
和Bar
存儲在嵌套的樹狀結構中?
謝謝PaulH
這是通過繼承的原始運行時多態性。
用從Base
繼承的純虛擬方法DoTheOutput
實現替換FooFunc
和BarFunc
,然后在循環中通過Base*
調用該方法。 如果您還需要Base
輸出,則Base::DoTheOutput
將不是純的,並且在子類實現完成派生特定於類的輸出之后將被子類實現調用。
如果需要在接口中保持BarFunc
和FooFunc
完整,可以將它們委托給新的DoTheOutput
函數。
首先,Bar類存在問題。 由於您使用的是std::vector< Base >
,因此將對象切片(即對象的Base部分的副本插入到矢量中,而不是對象)。 您將要使用std::vector< Base* >
,它是指針的向量。
其次,要執行所需的操作,可以在Foo和Bar類都覆蓋的Base類中使用虛擬方法。 如果您認為您的應用程序需要多個遍歷操作之一,則可以查看Visitor模式 。
好的,根據Alf的建議,我正在將我的評論作為答案。
即使RTTI在這里也不起作用,因為您將Base
對象存儲在向量中。 這些對象將被切片 ,從而失去派生類的任何信息。 您需要存儲Base
指針,最好是智能指針。 此外,您沒有虛擬功能。 RTTI需要至少一個虛擬功能才能工作。
使您的函數成為Base
的純虛擬方法,然后以適當的行為在每個派生類中重寫它。 這將使Base
成為抽象類,從而使切片問題成為不可能。
聽起來您想使用多態性。 創建一個虛函數並讓子類實現它。 然后使您的列表成為指向基址的指針列表:
class Base
{
public:
virtual const char *Func() = 0; // pure virtual, no implementation
};
class Foo: public Base
{
public:
virtual const char *Func() { return "Hello from foo!"; }
};
class Bar: public Base
{
public:
virtual const char *Func() { return "Hello from bar!"; }
};
int main()
{
std::list<Base*> myList;
myList.push_back(new Foo());
myList.push_back(new Bar());
for( std::list<Base*>::const_iterator it = myList.begin();
it != myList.end();
++it )
{
printf( "%s ", (*it)->Func() );
}
// don't forget to delete your pointers. Or better yet, use smart pointers
return 0;
}
我有一個Visual Studio 2008 C ++應用程序,它具有從同一基礎派生的幾種對象。 ...這些對象存儲在std :: vector <Base>中。 我需要輸出每個Foo和Bar類中的信息以及存儲在基礎中的信息。 但是,我想避免使用RTTI。 ...我可以對此設計進行哪些更改,從而避免使用RTTI作為解決方案,但仍然允許我將具有不同功能的對象(如Foo和Bar)存儲在嵌套的樹狀結構中?
重要說明 :您說使用的是std::vector<Base>
,如果是這樣,則需要更改為std::vector<Base*>
(或Boost指針容器),以避免對象切片。
摘要 :您有一個基類和從其派生的類。 您希望從基類派生的類基於它們的實際作用來做事,還希望基類提供對從其派生的所有類有意義的方法。
答 :適當地重命名FooFunc
和BarFunc
。 讓它們覆蓋基類中的virtual
函數:
class Base {
public:
std::string Time() const { /*return formatted time*/; };
// this is a pure virtual function (the "= 0" part)
// there are other kinds of virtual functions that would also work
virtual const char* Func() const = 0;
private:
SYSTEMTIME time_;
};
class Foo : public Base {
public:
const char* Func() const { return "Hello from foo!"; };
};
typedef std::vector<Base*> BaseList;
class Bar : public Base
{
public:
const char* Func() 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_;
};
int main( int, char** )
{
BaseList list;
Foo foo;
Bar bar;
Foo foo2;
// you normally don't want to do it this way, but since the
// container won't outlive the stack objects you'll be safe.
list.push_back(&foo);
list.push_back(&bar);
bar.push_back(&foo2);
for(BaseList::const_iterator it = list.begin();
it != list.end();
++it )
{
// the "extra" * was added because the list is a vector<Base*>
// instead of a vector<Base>
printf("%s ", *it->Time());
// print Foo information for objects of type Foo
// OR print Bar information for objects of type Bar.
printf("%s\n", *it->Func());
// Descend in to objects of type Bar to print its children.
// This you'll need to use RTTI to know when you're looking at a
// Bar object and need to descend into it
bar* = dynamic_cast<Bar*>(*it);
if (bar == NULL)
continue;
for (BaseList::const_iterator bit = bar->begin(); bit != bar->end(); ++bit)
printf("\t%s\n", bit->Func());
}
return 0;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.