C++ 继承返回*this的成员函数

C++ 继承返回*this的成员函数,c++,inheritance,this,C++,Inheritance,This,为什么派生类的*此仍然是基本类型 我以为typename X会解决这个问题 如果这看起来很难看,有什么更好的办法 失败的尝试: template <typename T> class Derived; template <typename T, typename X> class Base{ public: T val; X f(void){ return *this; } }; temp

为什么
派生类的
*此
仍然是
基本
类型

我以为
typename X
会解决这个问题

如果这看起来很难看,有什么更好的办法

失败的尝试:

template <typename T>
class Derived;

template <typename T, typename X>
class Base{
    public:
        T val;
        X f(void){
            return *this;
        }
};

template <typename T>
class Derived: public Base<T, Derived<T> >{
};


int main(void){
    Derived<int> B;
    Derived<int> C = B.f();
}
模板
类派生;
模板
阶级基础{
公众:
T值;
X f(无效){
归还*这个;
}
};
模板
派生类:公共基{
};
内部主(空){
衍生B;
导出C=B.f();
}
错误:

test4.cpp(9): error: no suitable user-defined conversion from "Base<int, Derived<int>>" to "Derived<int>" exists
              return *this;
                     ^
          detected during instantiation of "X Base<T, X>::f() [with T=int, X=Derived<int>]" at line 20

compilation aborted for test4.cpp (code 2)
test4.cpp(9):错误:不存在从“基本”到“派生”的合适的用户定义转换
归还*这个;
^
在第20行实例化“X Base::f()[with T=int,X=Derived]”时检测到
test4.cpp的编译中止(代码2)

您可以通过以下方式进行向下广播:

X f(){ return static_cast<X&>(*this);} 
xf(){return static_cast(*this);}

您可以通过以下方式进行向下广播:

X f(){ return static_cast<X&>(*this);} 
xf(){return static_cast(*this);}
您有

X f(void){
    return *this;
}
在此函数中,
*this
的类型仍然是基类类型。没有从基类型到
X
的自动转换

我无法建议一个干净的解决方案,因为
X
在这一点上可以是任何东西,而不一定是
派生的

我可以使用:

template <typename T>
class Derived2 : public Base<T, double>
{
};
然后,您可以使用:

X& f(void){
    return static_cast<X&>(*this);
}
X&f(无效){
返回静态_cast(*此);
}
请注意,我将返回类型从
X
更改为
X&
。它避免了每次调用函数时制作副本的成本。

X f(void){
    return *this;
}
在此函数中,
*this
的类型仍然是基类类型。没有从基类型到
X
的自动转换

我无法建议一个干净的解决方案,因为
X
在这一点上可以是任何东西,而不一定是
派生的

我可以使用:

template <typename T>
class Derived2 : public Base<T, double>
{
};
然后,您可以使用:

X& f(void){
    return static_cast<X&>(*this);
}
X&f(无效){
返回静态_cast(*此);
}

请注意,我将返回类型从
X
更改为
X&
。它避免了每次调用函数时制作副本的成本。

当编译器查看
类基时,它没有理由相信实际上存在继承自它的
派生的
。可以执行
class Other:public Base{}
,并且从
class Base
Derived
的转换将不正确,因此不允许自动转换


如果您制定了一条规则,规定第二个模板参数必须是继承该基的派生类型(这违反了
class Other
),则可以通过强制转换绕过类型系统,但是要确保没有违反规则。

当编译器查看
类库时,没有理由相信实际上有一个继承自它的
派生的
。可以执行
class Other:public Base{}
,并且从
class Base
Derived
的转换将不正确,因此不允许自动转换


如果您制定了一个规则,规定第二个模板参数必须是继承该基的派生类型(这是
class Other
违反的),那么您可以通过强制转换绕过类型系统,但确保不违反该规则。

首先,我将修改
base
,使其只接受一个模板参数。
这样,它与CRTP习语的常见形式完全匹配。
实际上,在我看来,没有理由在这种情况下同时使用
T
Derived
作为模板参数,因为后者已经包含了前者和
T,Derived
是您想要遵循的模式:

template<typename>
class Base;

template <typename T, template<typename> typename X>
class Base<X<T>> {
    // ...
};

template <typename T>
class Derived: public Base<Derived<T>>{
    // ....
};
模板
阶级基础;
模板
阶级基础{
// ...
};
模板
派生类:公共基{
// ....
};
然后您可以从底部使用@Jarod42提到的促销:

X<T> f(void) {
    return *static_cast<X<T>*>(this);
}
xf(无效){
返回*static_cast(此);
}
请注意,这里您正在系统地制作对象的副本,可能它不是您想要的

另一个选项是稍微修改架构并使用协变返回类型(它遵循一个最小的工作示例):

模板
阶级基础{
T值;
公众:
虚常数基&f(void)常数{
归还*这个;
}
};
模板
派生类:公共基{
公众:
虚常量派生&f(void)常量{
归还*这个;
}
};
内部主(空){
衍生B;
派生C=B.f();
}

哪个更适合您主要取决于实际问题。

首先,我将修改
Base
,使其只接受一个模板参数。
这样,它与CRTP习语的常见形式完全匹配。
实际上,在我看来,没有理由在这种情况下同时使用
T
Derived
作为模板参数,因为后者已经包含了前者和
T,Derived
是您想要遵循的模式:

template<typename>
class Base;

template <typename T, template<typename> typename X>
class Base<X<T>> {
    // ...
};

template <typename T>
class Derived: public Base<Derived<T>>{
    // ....
};
模板
阶级基础;
模板
阶级基础{
// ...
};
模板
派生类:公共基{
// ....
};
然后您可以从底部使用@Jarod42提到的促销:

X<T> f(void) {
    return *static_cast<X<T>*>(this);
}
xf(无效){
返回*static_cast(此);
}
请注意,这里您正在系统地制作对象的副本,可能它不是您想要的

另一个选项是稍微修改架构并使用协变返回类型(它遵循一个最小的工作示例):

模板
阶级基础{
T值;
公众:
虚常数基&f(void)常数{
归还*这个;
}
};
模板
派生类:公共基{
公众:
虚常量派生&f(void)常量{
归还*这个;
}
};
内部主(空){
衍生B;
派生C=B.f();
}

哪个更适合你主要取决于实际问题。

f
的成员函数