我正在为以下情况寻找一个干净的C ++习语:
class SomeLibraryClass {
public:
SomeLibraryClass() { /* start initialization */ }
void addFoo() { /* we are a collection of foos */ }
void funcToCallAfterAllAddFoos() { /* Making sure this is called is the issue */ }
};
class SomeUserClass : public SomeLibraryClass {
public:
SomeUserClass() {
addFoo();
addFoo();
addFoo(); // SomeUserClass has three foos.
}
};
class SomeUserDerrivedClass : public SomeUserClass {
public:
SomeUserDerrivedClass() {
addFoo(); // This one has four foos.
}
};
所以,我真正想要的是SomeLibraryClass在构造过程结束时强制执行funcToCallAfterAllAddFoos的调用。用户不能将它放在SomeUserClass :: SomeUserClass()的末尾,这会弄乱SomeUserDerrivedClass。如果他把它放在SomeUserDerrivedClass的末尾,那么它永远不会被SomeUserClass调用。
为了进一步阐明我的需要,想象一下/ * start initialization * /获取一个锁,并且funcToCallAfterAllAddFoos()释放一个锁。
编译器知道对象的所有初始化何时完成,但是我可以通过一些不错的技巧获取该信息吗?
答案 0 :(得分:9)
我可能会用某种工厂来实现它。以下代码应该被读作伪代码,我还没有尝试编译它或任何东西。
class LibraryClass
{
public:
template<typename D>
static D *GetNewInstance()
{
// by assigning the new D to a LibraryClass pointer, you guarantee it derives from LibraryClass at compile time
// that way, the user can't accidentally type "LibraryClass::GetNewInstance<int>()" and have it work
LibraryClass *c = new D();
c->funcToCallAfterAllAddFoos();
return c;
}
...
};
答案 1 :(得分:5)
我不确定这是可能的。但是,你可以稍微重新设计一下:给你的基类构造函数一个参数std::vector<Foo> const &foosToBeAdded
,让派生类传递正确的foo
:
class SomeLibraryClass {
public:
SomeLibraryClass(std::vector<Foo> const &foosToBeAdded) {
/* start initialization */
std::for_each(foosToBeAdded.begin(), foosToBeAdded.end(),
std::bind1st(std::mem_fun(&SomeLibraryClass::addFoo), this));
funcToCallAfterAllAddFoos();
}
private:
void addFoo(Foo const &someFoo) { /* we are a collection of foos */ }
void funcToCallAfterAllAddFoos() { /* this is now called at the right time */ }
};
class SomeUserClass : public SomeLibraryClass {
public:
SomeUserClass() :
SomeLibraryClass(makeAFooVector())
{
}
private:
std::vector<Foo> makeAFooVector() { /* return a vector with three Foos */ }
};
通过让SomeUserClass
构造函数也收到vector
Foo
s,可以扩展模式。然后,在调用基类构造函数之前,它会将自己的Foo
添加到列表中。
您也可以传递迭代器而不是vector
s。留下来作为练习。
答案 2 :(得分:0)
试试Non-virtual Interface Idiom。使您的公共方法非虚拟,但让它调用私有虚方法。派生类重写此私有虚方法(是的,派生类可以覆盖私有虚拟)。将锁定内容放在公共非虚方法中,围绕私有虚方法的调用。
编辑: 在仔细查看代码之后,我认为你可能最好在基类中使用一个构造函数来接受一个Foo对象的容器并添加它们。
答案 3 :(得分:0)
由于C ++不允许反射,不能,您无法直接获取此信息。 (虽然可能有某些方法我不知道阻止编译成功)
但是,我在这里质疑设计。一旦SomeLibraryClass完成,释放锁是不是更有意义?如果您担心多次调用AddFoo的效率,您的库可以提供接受std::vector<Foo>
的成员,该成员只需获取并释放一次锁。
答案 4 :(得分:0)
为什么要提供公共addfoo方法?你说它是全部初始化,所以让集合被赋予构造函数。
然后,您可以从构造函数
调用非虚拟functocall