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