C++ 返回型协变

C++ 返回型协变,c++,templates,inheritance,iterator,C++,Templates,Inheritance,Iterator,为什么会发生无效协变返回类型错误 我试图实现一个基于模板的迭代器和一个派生迭代器 代码: 模板 基类A{ 公众: 虚拟布尔运算符!=(常量BaseClassA&A)常量{} 虚拟BaseClassA运算符++(T{} } ; 模板 类DerivedClassA:公共BaseClassA{ 私人: T*p; 公众: DerivedClassA运算符++(T){ DerivedClassA tmp(*本); ++p; 返回tmp; } 布尔运算符!=(常量DerivedClassA&A)常量{ 回报

为什么会发生
无效协变返回类型
错误

我试图实现一个基于模板的迭代器和一个派生迭代器

代码:

模板
基类A{
公众:
虚拟布尔运算符!=(常量BaseClassA&A)常量{}
虚拟BaseClassA运算符++(T{}
} ;
模板
类DerivedClassA:公共BaseClassA{
私人:
T*p;
公众:
DerivedClassA运算符++(T){
DerivedClassA tmp(*本);
++p;
返回tmp;
}
布尔运算符!=(常量DerivedClassA&A)常量{
回报率(A.p!=p);
} 
} ;
模板
B类{
私人:
BaseClassA开始者;
BaseClassaEnditer;
公众:
虚拟BaseClassA开始(void){}
虚拟BaseClassA结束(无效){}
} ;
模板
类派生类B{
私人:
DerivedClassA beginIter;
DerivedClassA endIter;
公众:
DerivedClassA开始(void){return beginter;}
DerivedClassA结束(无效){return endIter;}
} ;
内部主(空){
B类;
B.开始()!=B.结束();
++B.开始();
}
编译器错误(g++)

test.cpp:在“类DerivedClassA”的实例化中:
测试cpp:35:26:从“类别衍生类别B”中需要
测试。cpp:43:24:从此处开始需要
test.cpp:12:27:错误:“DerivedClassA DerivedClassA::operator++(T)[带T=int]的]的协变返回类型无效
DerivedClassA运算符++(T){
^
test.cpp:5:31:错误:重写'BaseClassA BaseClassA::operator++(T)[with T=int]'
虚拟BaseClassA运算符++(T{}
^
test.cpp:在函数“int main()”中:
test.cpp:45:5:错误:与“operator++”不匹配(操作数类型为“DerivedClassA”)
++B.开始();
^
测试。cpp:45:5:注:候选人为:
test.cpp:12:27:注意:DerivedClassA DerivedClassA::operator++(T)[带T=int]
DerivedClassA运算符++(T){
^
test.cpp:12:27:注意:候选者需要1个参数,提供0个参数

C++仅直接支持原始指针和原始引用的协变结果类型

一个原因是,对于类类型,协变结果可能需要比调用方(仅知道基类声明)为该结果留出的空间更多的空间

示例中的模板与此问题无关


其他消息:

  • 您不需要虚拟的
    运算符==
    ,因为您不需要运行时检查相等比较的有效性,实际上您不需要

  • operator++()
    operator++(int)
    是仅有的两个有效签名,因此无法对参数类型进行有意义的模板化


C++仅直接支持原始指针和原始引用的协变结果类型

一个原因是,对于类类型,协变结果可能需要比调用方(仅知道基类声明)为该结果留出的空间更多的空间

示例中的模板与此问题无关


其他消息:

  • 您不需要虚拟的
    运算符==
    ,因为您不需要运行时检查相等比较的有效性,实际上您不需要

  • operator++()
    operator++(int)
    是仅有的两个有效签名,因此无法对参数类型进行有意义的模板化


C++内置协方差适用于C++对象模型中的引用和指针。

现在是C++。所以如果你不喜欢C++提供的东西,你可以编写你自己的对象模型。

在您的情况下,您有迭代器。这些迭代器希望是值类型(因为这是C++在库中想要的),并且希望它们是多态的。

多态值类型不受C++对象模型的支持。 使用或可以创建支持值类型多态性的ducktype多态性系统

现在,您的
BaseClassB::begin
end
返回一个
任意迭代器
。与此概念匹配的内容,包括
DerivedClassA
,可以在其中存储和操作。
BaseClassA
变得过时,因为类型擦除迭代器不需要虚拟基类来实现多态性

DerivedClassB
还返回一个
any\u迭代器
。如果您想要裸访问
DerivedClassB
的真实迭代器,请使用名为
get\u裸范围()的函数
返回
DerivedClassB
的裸迭代器,可在绝对确定类型为
DerivedClassB
的上下文中使用。如果这样做,还可以将
开始
结束
标记为
最终


注意,这种类型的擦除会有运行时的成本,迭代它会比“原始裸”迭代慢。这只不过是在高性能上下文中做得很低的一个问题,不要让它吓跑你。

< P> C++内置的协方差适用于C++对象模型中的引用和指针。

现在是C++。所以如果你不喜欢C++提供的东西,你可以编写你自己的对象模型。

在您的情况下,您有迭代器。这些迭代器希望是值类型(因为这是C++在库中想要的),并且希望它们是多态的。

多态值类型不受C++对象模型的支持。 使用或可以创建支持值类型多态性的ducktype多态性系统

现在,您的
BaseClassB::begin
end
返回一个
任何迭代器
。与该概念匹配的内容,包括
DerivedClassA
,可以在其中存储和操作。
BaseClassA
变得过时,因为类型擦除迭代器不需要虚拟基类
template <typename T>
class BaseClassA{
    public:
        virtual bool operator!=(const BaseClassA<T> & A) const {}
        virtual BaseClassA<T> operator++(T){}
} ;
template <typename T>
class DerivedClassA: public BaseClassA<T>{
    private:
        T* p;
    public:
        DerivedClassA<T>  operator++(T){
            DerivedClassA<T> tmp(*this);
            ++p;
            return tmp;
        }
        bool operator!=(const DerivedClassA<T> & A) const {
            return (A.p != p);
        } 
} ;

template <typename T>
class BaseClassB{
    private:
        BaseClassA<T> beginIter;
        BaseClassA<T> endIter;
    public:
        virtual BaseClassA<T> begin(void){}
        virtual BaseClassA<T> end(void){}
} ;

template <typename T>
class DerivedClassB{
    private:
        DerivedClassA<T> beginIter;
        DerivedClassA<T> endIter;
    public:
        DerivedClassA<T> begin(void){ return beginIter; }
        DerivedClassA<T> end(void){ return endIter; }
} ;

int main(void){
    DerivedClassB<int> B;
    B.begin() != B.end();
    ++B.begin();
}
test.cpp: In instantiation of 'class DerivedClassA<int>':
test.cpp:35:26:   required from 'class DerivedClassB<int>'
test.cpp:43:24:   required from here
test.cpp:12:27: error: invalid covariant return type for 'DerivedClassA<T> DerivedClassA<T>::operator++(T) [with T = int]'
         DerivedClassA<T>  operator++(T){
                           ^
test.cpp:5:31: error:   overriding 'BaseClassA<T> BaseClassA<T>::operator++(T) [with T = int]'
         virtual BaseClassA<T> operator++(T){}
                               ^
test.cpp: In function 'int main()':
test.cpp:45:5: error: no match for 'operator++' (operand type is 'DerivedClassA<int>')
     ++B.begin();
     ^
test.cpp:45:5: note: candidate is:
test.cpp:12:27: note: DerivedClassA<T> DerivedClassA<T>::operator++(T) [with T = int]
         DerivedClassA<T>  operator++(T){
                           ^
test.cpp:12:27: note:   candidate expects 1 argument, 0 provided