Kno*_*abe 1 c++ constructor-overloading c++11 universal-reference
当派生类复制和移动函数调用它们的基类版本时,我对我所看到的行为感到困惑.
我有一个基类与各种构造函数,告诉我什么时候被调用:
#include <iostream>
class Base {
public:
Base() {}
template<typename T>
Base(T&&) { std::cout << "URef ctor\n"; }
Base(const Base&) { std::cout << "Copy ctor\n"; }
Base(Base& rhs): Base(const_cast<const Base&>(rhs))
{ std::cout << " (from non-const copy ctor)\n"; }
Base(Base&&) { std::cout << "Move ctor\n"; }
Base(const Base&& rhs): Base(rhs)
{ std::cout << " (from const move ctor)\n"; }
};
Run Code Online (Sandbox Code Playgroud)
对于具有编译器生成的复制和移动操作的派生类
class Derived: public Base {};
Run Code Online (Sandbox Code Playgroud)
和这个测试代码,
int main()
{
Derived d;
Derived copyNCLValue(d);
Derived copyNCRvalue(std::move(d));
const Derived cd;
Derived copyCLValue(cd);
Derived copyCRvalue(std::move(cd));
}
Run Code Online (Sandbox Code Playgroud)
gcc 4.8.1产生这个输出:
Copy ctor
Move ctor
Copy ctor
Copy ctor
Run Code Online (Sandbox Code Playgroud)
这让我感到惊讶.我期望调用通用引用的基类构造函数被调用,因为它可以被实例化以在派生对象上创建完全匹配,这可能是从派生类的函数传递的.基类复制和移动函数需要派生到基础的转换.
如果我更改派生类以自己声明副本并移动函数,但是为它们提供默认实现,
class Derived: public Base {
public:
Derived(){}
Derived(const Derived& rhs) = default;
Derived(Derived&& rhs) = default;
};
Run Code Online (Sandbox Code Playgroud)
gcc产生相同的输出.但是如果我自己用我认为默认的实现来编写函数,
class Derived: public Base {
public:
Derived(){}
Derived(const Derived& rhs): Base(rhs) {}
Derived(Derived&& rhs): Base(std::move(rhs)) {}
};
Run Code Online (Sandbox Code Playgroud)
我得到了我原先预期的输出:
URef ctor
URef ctor
URef ctor
URef ctor
Run Code Online (Sandbox Code Playgroud)
我期望在每种情况下获得相同的输出.这是gcc中的一个错误,还是有些东西我不理解?
这让我感到惊讶.我期望调用通用引用的基类构造函数被调用,因为它可以被实例化以在派生对象上创建完全匹配,这可能是从派生类的函数传递的.基类复制和移动函数需要派生到基础的转换.
Derived copyCRvalue(std::move(cd));不会.编译器会看到真正含义的行,Derived copyCRvalue(static_cast<const Derived&&>(cd));它会尝试找到Derived与该调用匹配的构造函数.它发现两个密切相关的构造函数都隐式声明:
Derived(Derived const &); // copy constructor
Derived(Derived &&); // move constructor
Run Code Online (Sandbox Code Playgroud)
第二个不能使用,因为rvalue-reference是一个const对象,但第一个是匹配.隐式定义的复制构造函数的定义是:
Derived(Derived const &rhs) : base(static_cast<Base const &>(rhs)) {}
Run Code Online (Sandbox Code Playgroud)
在构造函数中,它rhs是一个左值,而不是一个右值(并且模板化的构造函数不是复制构造函数).
但是如果我自己用我认为默认的实现来编写函数,
class Derived: public Base {
public:
Derived(){}
Derived(const Derived& rhs): Base(rhs) {}
Derived(Derived&& rhs): Base(std::move(rhs)) {}
};
Run Code Online (Sandbox Code Playgroud)
除了那些不是编译器将提供的定义.该标准的具体配额为12.8/15
非联合类X的隐式定义的复制/移动构造函数执行其基础和成员的成员复制/移动.
也就是说,隐式定义的构造函数将使用源的基础初始化目标的基础,并且类似地,源中具有相同成员的目标中的每个成员.
| 归档时间: |
|
| 查看次数: |
124 次 |
| 最近记录: |