gpt4 book ai didi

c++ - 重载函数和继承

转载 作者:IT老高 更新时间:2023-10-28 21:44:39 26 4
gpt4 key购买 nike

如果我使用给定的类 MyClass 或任何派生类 MyClassDer 调用它,我正在尝试重载一些模板函数以执行特定操作。代码如下:

#include <iostream>

struct MyClass {
virtual void debug () const {
std::cerr << "MyClass" << std::endl;
};
};

struct MyClassDer : public MyClass {
virtual void debug () const {
std::cerr << "MyClassDer" << std::endl;
};
};

template <typename T> void func (const T& t) {
std::cerr << "func template" << std::endl;
}

void func (const MyClass& myClass) {
std::cerr << "func overloaded" << std::endl;
myClass.debug ();
}


int main(int argc, char **argv) {
func (1);
MyClass myClass;
func (myClass);
MyClassDer myClassDer;
func (myClassDer);
}

输出是:

func template
func overloaded
MyClass
func template

func (myClassDer) 调用模板函数而不是 void func (const MyClass& myClass)。我该怎么做才能获得预期的行为?

谢谢

最佳答案

这就是重载解析的工作原理。当查找完成时,它会同时找到模板和函数。然后推导出模板类型并开始重载决议。对于 MyClass 类型的参数,两个候选者是:

void func<MyClass>(MyClass const&);
void func(MyClass const&);

这对于参数来说同样是很好的匹配,但第二个是非模板是首选。 MyClassDer 的情况:

void func<MyClassDer>(MyClassDer const&);
void func(MyClass const&);

在这种情况下,第一个比第二个更好,因为第二个需要派生到基础的转换,并且被选中。

有不同的方法可以直接调度以命中您的代码。最简单的只是将参数的类型强制为 MyClass 并因此回退到原始情况:

func(static_cast<MyClass&>(myClassDer));

虽然很简单,但这需要在任何地方完成,如果你只忘记一个地方,就会调用错误的东西。其余的解决方案是复杂的,您可能要考虑是否只提供不同的函数名称会更好。

当类型派生自 MyClass 时,其中一个选项是使用 SFINAE 禁用模板:

template <typename T>
typename std::enable_if<!std::is_base_of<MyClass,MyClassDer>::value>::type
func(T const & t) { ... }

在这种情况下,查找后,编译器会进行类型推导,将T推导出为MyClassDer,然后计算函数的返回类型(SFINAE 也可以应用于另一个模板或函数参数)。 is_base_of 将产生 falseenable_if 不会有嵌套类型。函数声明格式不正确,编译器将删除它,将解析集保留为单个候选者,即非模板重载。

另一种选择是提供单个模板接口(interface),并使用标签调度在内部调度模板或重载(使用不同的名称)。这个想法是相似的,你在模板中评估特征并调用一个函数,该函数具有从该评估生成的类型。

template <typename T>
void func_impl(T const&, std::false_type) {...}
void func_impl(MyClass const&, std::true_type) {...}

template <typename T>
void func(T const &x) {
func_impl(x,std::is_base_of<MyClass,MyClassDer>::type());
}

还有其他选择,但这是两种常见的,其余的主要基于相同的原则。

再次考虑问题是否值得解决方案的复杂性。除非对 func 的调用本身是在通用代码中完成的,否则只需更改函数名称即可解决问题,而不会不必要地增加您或其他维护者可能难以维护的复杂性。

关于c++ - 重载函数和继承,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18982093/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com