c++ - 转发构造函数调用 2 次基类的复制构造函数

标签 c++ c++11 constructor

以下代码将构造函数从基类转发到派生类。

为什么调用 2 个复制构造函数?后台发生了什么?

用 g++ 编译。

#include <iostream>
using namespace std;

struct A {
    A() { cout << "A" << endl; }
    A(const A&) { cout << "A(const A&)" << endl; }
    template<typename T> A(T a); // Needed to compile :-O
};

template<typename T>
struct C : public T { using T::T; };

int main()
{
    A a;
    C<A> ca(a);
    //C<A> caa(ca);
    return 0;
}

输出是:

A
A(const A&)
A(const A&)

最佳答案

通过在 A 中定义构造函数模板, C将获得具有类似签名的构造函数模板。它的隐式定义类似于:

template<typename T>
struct C : public T
{
    //using T::T;

    C() = default;
    C(C const&) = default;

    template<typename U> C(U a) : T( std::forward<U>(a) ) {}
};

这现在调用了 A 的复制构造函数两次:一次用于按值获取参数。第二次调用来自 T( std::forward<U>(a) )调用 A 的拷贝函数.这让我感到惊讶,因为您会期望一个继承 构造函数调用它所继承的基类的确切构造函数。但事实并非如此,重载决议选择的不是A的ctor模板。 ,但是普通的复制函数 A(A const&) (见下文)。


有趣的是,它并不关心A 中的构造函数模板是什么。确实如此,它只需要声明。这就是为什么在 OP 中,定义可能会丢失;它也可以被删除(这可能是一个缺陷?)。

A 的拷贝者仅需在初始化的重载解析期间选择 T( std::forward<U>(a) ) .这里就是这种情况:参数是类型为 A 的右值。 , 它可以直接绑定(bind)到 const A&引用,根据 A 的复制构造函数的要求。由于引用绑定(bind)是直接的并且没有派生到基础的转换,因此复制构造函数被列为完全匹配。 A 中的 ctor 模板也被评为完全匹配,但由于在重载集中有一个具有相同等级的模板函数和非模板函数,因此首选非模板函数(复制构造函数 A(A const&) )。

关于c++ - 转发构造函数调用 2 次基类的复制构造函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20734841/

相关文章:

c++ - 使用线程和 this_thread::yield 来确定打印顺序

c++ - 使用 delete 运算符删除结构中的元素

c# - 我可以在 C# 中使用 C header 作为协议(protocol)吗

c++ - 添加 long 值显示不同的 o/p

c++ - regex_replace,为什么它会丢失 $1?

c++ - 防止构造函数参数隐式转换为外部库类型

c++ - QT 无法读取文件

c++ - 显式复制构造函数编译错误

c++ - 为什么当它作为静态成员变量出现时没有调用c++构造函数?

Groovy:有没有在参数拷贝后调用的构造函数?