我对派生类复制和移动函数调用其基类版本时看到的行为感到困惑。
我有一个带有各种构造函数的基类,它们告诉我何时调用它们:
#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"; }
};
对于具有编译器生成的复制和移动操作的派生类
class Derived: public Base {};
和这个测试代码,
int main()
{
Derived d;
Derived copyNCLValue(d);
Derived copyNCRvalue(std::move(d));
const Derived cd;
Derived copyCLValue(cd);
Derived copyCRvalue(std::move(cd));
}
gcc 4.8.1 产生这个输出:
Copy ctor
Move ctor
Copy ctor
Copy ctor
这让我很惊讶。我希望调用采用通用引用的基类构造函数,因为它可以被实例化以在可能从派生类的函数传递的派生对象上创建精确匹配。基类复制和移动函数需要派生到基类的转换。
如果我更改派生类以自己声明复制和移动函数,但给它们默认实现,
class Derived: public Base {
public:
Derived(){}
Derived(const Derived& rhs) = default;
Derived(Derived&& rhs) = default;
};
gcc 产生相同的输出。但是,如果我自己用我认为是默认实现的方式编写函数,
class Derived: public Base {
public:
Derived(){}
Derived(const Derived& rhs): Base(rhs) {}
Derived(Derived&& rhs): Base(std::move(rhs)) {}
};
我得到了我最初期望的输出:
URef ctor
URef ctor
URef ctor
URef ctor
我希望在每种情况下都能得到相同的输出。这是 gcc 中的错误,还是我不理解的地方?