c++ - 使用子类调用时重载函数模板匹配模板而不是基类

标签 c++

考虑以下代码:

#include <cstdlib>
#include <iostream>

using std::cout;
using std::endl;

class A { 
public:
    virtual ~A() { 

    }
};

class B : public A {

};

void foo(A& a) {
    cout << "A&" << endl;
}

void foo(const A& a) {
    cout << "const A&" << endl;
}

void foo(A* a) {
    cout << "A*" << endl;
}

void foo(const A* a) {
    cout << "const A*" << endl;
}

template <class T>
void foo(T& a) {
    cout << "T&" << endl;
}

template <class T>
void foo(const T& a) {
    cout << "const T&" << endl;
}

template <class T>
void foo(T* a) {
    cout << "T*" << endl;
}

template <class T>
void foo(const T* a) {
    cout << "const T*" << endl;
}

int main(int argc, char** argv) {
    B a;
    foo(a);

    B& b = a;
    foo(b);

    B* c = &a;
    foo(c);

    const B& d = a;
    foo(d);

    const B* e = &a;
    foo(e);

    return EXIT_SUCCESS;
}

产生以下输出:

T&
T&
T*
const T&
const T*

这个输出让我感到惊讶,因为我认为最接近匹配的函数将被调用。所以我期待输出:

A&
A&
A*
const A&
const A*

有人可以解释为什么当我传入基类 (A) 的子类 (B) 时选择模板函数重载而不是基类重载吗?

最佳答案

这是预期的行为。当你调用 foo(a); 时,a 是一个 B。所以我们需要从 BA 的隐式转换,以便调用 void foo(A& a)。但是因为你也有

template <class T>
void foo(T& a) {
    cout << "T&" << endl;
}

模板被删除,你得到 void foo(B& a)。这是直接匹配,不需要转换。这是最好的功能,所以这就是它被选中的原因。这对于所有其他函数都是相同的,T 被推导为 B,这比所有 A 函数提供更好的匹配.

如果你想停止这个,你可以使用 std::enable_if并检查类型是否为派生类 std::is_base_of

关于c++ - 使用子类调用时重载函数模板匹配模板而不是基类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39044153/

相关文章:

c++ - 无法从 char 三重指针获取或打印 wstring 元素

c++ - 如何在 C++ Linux 中使用 ICU 库将 UnicodeString 转换为 windows-1251?

c++ - boost::asio::strand::dispatch(handle) 还是直接调用句柄?

c++ - 何时以及如何决定是否使用 Actor 阵容?

c++ - 无法读取客户端发送的所有消息

c++11 shared_ptr + Boost::序列化

c++ - 标准输入C++

c++ - 类对象指针不会分配给字符串

c++如何使两个 vector 一个带有数据另一个指向并且只读

c++ - 在 C++ 中,当你制作多个类时,你是否应该将它们分别放在它们自己的 .cpp/.h 对中?