模板化子类的无效协变返回类型

Cor*_*y-G 0 c++ virtual templates covariance

我有一个继承自父类的子类,但是孩子也会选择一个模板参数.这两个类都有一个'clone'函数,只调用它们的复制构造函数.我想将副本设为虚拟,以便子类始终将其称为自己的副本.

以下是问题的简化版本:

#include <iostream>
using namespace std;

class Parent
{
public:
    virtual Parent foo() { cout << "Parent Foo\n"; return *this; }
};

template <class T>
class Child : public Parent
{
public:
    Child<T> foo() { cout << "Child Foo\n"; return *this; }
};

int main()
{
    Child<int> c;

    c.foo();

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

似乎Child类应该与Parent类协变.我错过了什么?有没有办法保持虚拟功能和模板?谢谢.

编辑

也许我之前的例子太简单了.这是一个扩展的简单示例:

#include <iostream>
using namespace std;

class Parent
{
public:
    Parent(){}
    virtual Parent clone() const { return Parent(*this); }
private:
    Parent( Parent const& cpy ) { };
};

template <class T>
class Child : public Parent
{
public:
    Child(){}
    Child<T> clone() const { return Child<T>(*this); }
private:
    Child( Child<T> const& cpy ) {};
};

int main()
{
    Child<int> c;
    Parent* pc = &c;
    pc->clone();

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我希望副本始终是通过复制虚拟副本的实际副本.我想避免返回指针,但看起来我将被迫返回指针以避免DieterLücking提到的切片问题.

小智 6

父和子类型不是协变的,而是父和子和.

#include <iostream>
using namespace std;

class Parent
{
public:
    virtual Parent& foo() = 0;
};

template <class T>
class Child : public Parent
{
public:
    Child& foo() { cout << "Child Foo\n"; return *this; }
};

int main()
{
    Child<int> c;
    Parent& parent = c.foo();
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

从10.3.7虚函数

重写函数的返回类型应与重写函数的返回类型相同或与函数类的协变相同.如果函数D :: f覆盖函数B :: f,则函数的返回类型如果满足以下条件则是协变的:

- 两者都是指向类的指针,都是对类的左值引用,或者两者都是对类112的右值引用

- 返回类型B :: f中的类与D :: f的返回类型中的类相同,或者是D类的返回类型中类的明确且可访问的直接或间接基类: :F

- 指针或引用都具有相同的cv限定,并且返回类型D :: f中的类类型具有与B :: f的返回类型中的类类型相同的cv-qualification或更少的cv-qualification.