我有一个C ++代码,目前看起来像这样:有一个类层次结构可以执行一些比较,还有一个使用它的列表类。在运行时基于某个模式对象确定要使用的比较操作。结构如下:
class A{
bool doComparison(const string& s1, const string& s2) const=0;
}
class B: public A{
bool doComparison(const string& s1, const string& s2) const {
...
}
}
class C: public A{
bool doComparison(const string& s1, const string& s2) const {
...
}
}
template <class, S>
public FancyList{
shared_ptr<A> z_;
vector<S> v;
FancyList(shared_ptr<A> z) : z_(z);
void DoSmth(){
....
z_->doComparison(arg1, arg2);
}
}
typedef FancyList<string> FancyStringList;
// Determine which comparison to use at runtime
shared_ptr<A> c = nullptr;
switch(type):
case int:
c = make_shared<B>();
break;
case double:
c = make_shared<B>();
break;
FancyStringList l(c);
l.push_back("stuff");
C#曾经是我的主要语言,所以这段代码对我来说似乎没问题。但我被告知这种方法的问题在于它使用虚函数,因此方法调用会有轻微的开销。什么是正确的C ++ - 重新组织此代码的方式,因此不需要具有此类层次结构而不需要使用虚函数?
答案 0 :(得分:1)
与您想要的相反,虚函数的开销是不可避免的,因为在运行时决定调用哪个实际函数。
如果决定始终在运行时进行,则编译器不能将函数调用硬编码到生成的机器代码中。它必须是间接函数调用:使用指针指向函数,并在函数调用之前取消引用指针。虚函数只是进行间接函数调用的一种方法。
模板是告诉编译器在编译期间生成代码的一种方式。在编译时做出决定时,所有模板都可以不引入开销。它无法帮助您删除必须在运行时完成的工作。
如果您仍然对使用模板感兴趣,可以考虑将比较器作为模板参数。
template <class T, class Comparator>
class MyList
{
std::vector<T> vec;
Comparator comp;
public:
void do_thing(const T& a, const T& b)
{
vec.push_back(a);
vec.push_back(b);
bool x = comp(vec[0], vec[1]); // for example
std::cout << x;
}
};
在比较器类中,重载函数调用操作符。
class Compare1
{
public:
bool operator()(const std::string& lhs, const std::string& rhs) const
{
return lhs < rhs;
}
};
class Compare2
{
public:
bool operator()(const std::string& lhs, const std::string& rhs) const
{
return lhs.size() < rhs.size();
}
};
int main()
{
MyList<std::string, Compare1> myli1;
myli1.do_thing("a", "b");
MyList<std::string, Compare2> myli2;
myli2.do_thing("c", "d");
}
您甚至可以隐藏比较器类后面的间接函数调用。但它并没有消除开销。
class A
{
public:
virtual bool doComparison(const std::string& s1, const std::string& s2) const=0;
virtual ~A() = default;
};
class PolymorphicComparator
{
private:
std::shared_ptr<A> comp;
public:
PolymorphicComp(std::shared_ptr<A> c) : comp(c) {}
bool operator()(const std::string& lhs, const std::string& rhs) const
{
return comp->doComparison(lhs, rhs);
}
};