【发布时间】:2013-10-30 04:19:33
【问题描述】:
考虑以下代码sn-p:
struct Base { virtual void func() { } };
struct Derived1 : Base { void func() override { print("1"); } };
struct Derived2 : Base { void func() override { print("2"); } };
class Manager {
std::vector<std::unique_ptr<Base>> items;
public:
template<class T> void add() { items.emplace_back(new T); }
void funcAll() { for(auto& i : items) i->func(); }
};
int main() {
Manager m;
m.add<Derived1>();
m.add<Derived2>();
m.funcAll(); // prints "1" and "2"
};
我正在使用virtual 调度,以便从多态对象的std::vector 调用正确的override 方法。
但是,我知道多态对象是什么类型,因为我在 Manager::add<T> 中指定了它。
我的想法是通过获取成员函数T::func() 的地址并将其直接存储在某处来避免virtual 调用。但是这是不可能的,因为我需要将其存储为 void* 并将其转换回 Manager::funcAll(),但我当时没有类型信息。
我的问题是:在这种情况下,对于多态性,我似乎拥有比平常更多的信息(用户在 Manager::add<T> 中指定派生类型 T) - 有什么方法可以使用此类型信息来防止看似不需要的virtual 电话? (不过,用户应该能够创建自己的类,这些类派生自其代码中的Base。)
【问题讨论】:
-
"我有什么办法可以使用这种类型的信息来防止看似不需要的虚拟呼叫?"不删除该信息? (
unique_ptr<Base>在此处输入擦除)。无论如何,“获取成员函数T::func()的地址并直接将其存储在某处”与虚拟调用几乎相同,只是您需要做更多的工作。 -
@R.MartinhoFernandes:我明白。然而,我看不到存储派生自
T的类型的另一种方式,即使在Manager::add<T>中指定了类型之后 - 请记住,用户应该定义自己的派生自Base的类型,所以我不不知道这些类型会是什么。 -
所以你想要的在语言中是不可能实现的(然而,编译器可以在这个示例代码中做这样的优化,但我怀疑你在实践中能找到)。这是一个经典的“你不能吃蛋糕也不能吃”的情况:要么删除类型,要么保留类型。
-
@R.MartinhoFernandes:好的,谢谢您的解释。
-
只是一条建议,不要使用继承,我想你会发现大多数时候使用模板和/或组合(而不是继承)就足够了,而且更好。举例来说,大多数标准库不使用继承
标签: c++ optimization c++11 polymorphism virtual