为什么来自覆盖类的指针使用运算符==和基类中的运算符!=
Why pointer from override class use operator== and operator!= from base class
我有用于类和类的迭代器模板,用于 for 语句。
template<class T>
class Itr2 {
public:
Itr2() { }
~Itr2() { }
typedef typename Itr2 type;
typedef typename T& reference;
virtual type& operator++() { return *this; }
virtual T& operator*() { return ((reference)*((type*)this)); }
virtual bool operator==(const type& o) const { return true; }
virtual bool operator!=(const type& o) const { return false; }
};
template<class T>
class I2
{
public:
typedef I2<T> type;
typedef T value;
typedef T& reference;
typedef typename Itr2<T> iterator;
virtual iterator& begin() { return *(new iterator()); }
virtual iterator& end() { return *(new iterator()); }
};
接下来,我为标准 std::vector<> 创建了类。
template<class T>
class ItrSTD : public Itr2<T> {
public:
typedef typename Itr2<T> base_type;
typedef typename ItrSTD<T> type;
typedef typename T& reference;
typedef typename std::vector<T>::iterator std_itr;
protected:
std_itr itr_;
public:
ItrSTD(const type& o) { itr_ = o.itr_; }
ItrSTD(const std_itr& o) { itr_ = o; }
virtual base_type& operator++() { itr_++; return *this; }
virtual T& operator*() { return ((reference)(*this->itr_)); }
bool operator==(const base_type& o) const override { return (((const type&)o).itr_ == this->itr_); }
bool operator!=(const base_type& o) const override { return (((const type&)o).itr_ != this->itr_); }
};
template<class T>
class VSTD : public I2<T> {
protected:
std::vector<T> arr_;
public:
typedef typename ItrSTD<T> iterator;
VSTD(const VSTD& o) { arr_ = o.arr_; }
template<typename ...E> VSTD(E&&...e) : arr_({ std::forward<T>(e)... }) { }
iterator& begin() _NOEXCEPT override{ return (*new iterator(arr_.begin())); }
iterator& end() _NOEXCEPT override{ return (*new iterator(arr_.end())); }
};
如果我使用 Direct 语句 for(int i:v)。 它工作正常,但是当我尝试从指针编译器执行此操作时,请使用基类运算符!=(而不是覆盖运算符!=)并且代码无法:(工作。
int v_i = 0;
VSTD<int> vstd_a = { 1, 2, 3 };
I2<int> *i2 = &vstd_a;
for (int j : *i2) //DOESN't work :( use operator!= from base class
{
v_i += j;
}
for (int j : vstd_a) //work fine :) use operator!= from VSTD.
{
v_i += j;
}
如果我简化代码:
template<typename T>
class I3
{
public:
T i;
virtual bool operator==(const I3& o) const { return false; }
};
template<typename T>
class I3O : public I3<T>
{
public:
virtual bool operator==(const I3& o) const override { return true; }
};
I3O<int> i3_a, i3_b; I3<int> *i3_ap, *i3_bp;
i3_ap = &i3_a; i3_bp = &i3_b; bool i3_c;
i3_c = (i3_a == i3_b);
i3_c = ((*i3_ap) == (*i3_bp));
两个结果都很好(返回 true)并从覆盖类进行比较(仅适用于( : ) 工作不好:(:
为什么会这样。是否可以将 for 语句用于模板指针?begin(), end() 函数工作正常。只有操作员的工作方式不同。
附言我使用VS2013编译器。
我没有看过你的代码中的细节,但是... 它看起来像您正在尝试使迭代器具有多态性。 标准但是,不断按值传递它们,并且按值传递不会支持多态性;它切片。 因此(我假设),在:
for ( int j : *i2 )
编译器为迭代器创建局部变量,其类型为静态确定。 虽然它调用了正确的begin()
,它将结果分配给此局部变量,从而对其进行切片。
如果需要多态迭代器,则需要实现信/信成语:
class Iterator
{
Iterator* myImpl;
virtual Iterator* clone() const { abort(); }
virtual T& current() const { abort(); }
virtual bool isEqual( Iterator const* other ) { abort(); }
virtual void next() { abort(); }
protected:
Iterator() : myImpl( nullptr ) {}
public:
Iterator( Iterator* impl ) : myImpl( impl ) {}
Iterator( Iterator const& other ) : myImpl( other.clone() ) {}
virtual ~Iterator() { delete myImpl; }
T& operator*() const
{
return myImpl->current();
}
bool operator==( Iterator const& other ) const
{
return myImpl->isEqual( other.myImpl );
}
Iterator& operator++()
{
myImpl->next();
return *this;
}
// ...
};
class DerivedIterator : public Iterator
{
Iterator* clone() const override { return new DerivedIterator( *this ); }
T& current() const override { ... }
bool isEqual( Iterator const* other ) override { ... }
virtual void next() { ... }
public:
DerivedIterator(...) ...
};
然后,派生的begin
和end
返回如下内容:
Iterator( new DerivedIterator(...) );
这在运行时相当昂贵,但这确实是唯一的方法提供多态性,并且仍然具有迭代器。
该标准定义了 [stmt.ranged]/1 中基于范围的 for 语句的语义:
对于表单的基于范围的
for
语句for ( for-range-declaration : expression ) statement
让 range-init 等效于用括号括起来的表达式
( expression )
以及基于范围的
for
形式的语句for ( for-range-declaration : braced-init-list ) statement
让 range-init 等效于大括号初始化列表。在每种情况下,基于范围的
for
语句等效于{ auto && __range = range-init; for ( auto __begin = begin-expr, __end = end-expr; __begin != __end; ++__begin ) { for-range-declaration = *__begin; statement } }
其中
确定如下:__range
、__begin
和__end
是仅为表达式定义的变量,_RangeT
是表达式的类型,开始-expr 和 end-expr(1.1) — 如果
_RangeT
是数组类型,...(1.2) — 如果
_RangeT
是类类型,则在类_RangeT
的范围内查找非限定 IDbegin
和end
,就像通过类成员访问查找一样 (3.4.5),如果其中一个(或两个)找到至少一个声明,则分别__range.begin()
和__range.end()
开始 expr 和结束 expr;(1.3) — 否则,...
程序中的第一个循环:
for (int j : *i2) //DOESN't work :( use operator!= from base class
{
v_i += j;
}
因此等效于:
{
auto && __range = (*i2);
for ( auto __begin = __range.begin(),
__end = __range.end();
__begin != __end;
++__begin ) {
int j = *__begin;
v_i += j;
}
}
由于I2<int>::begin
和I2<int>::end
的返回类型是Itr2<int>&
,__begin
和__end
将被推导出为Itr2<int>
类型,并从I2<int>::begin()
和I2<int>::end()
的返回值构造副本。当然,该复制构造对返回的类型进行切片,最终会得到基类型的实例。
- 如何使基类的运算符对基类的可变参数数可见(请参阅下面的代码)?
- 基类和派生类的多态赋值运算符
- 模板基类中的重载运算符
- 为什么基类中的复制和交换会导致派生类中的复制赋值运算符被隐式删除?
- 如何从派生类访问基类中的重载运算符?
- 基类和派生类的虚拟插入运算符重载
- 派生类 插入和提取运算符重载以及基类与派生类之间的强制转换
- 如何在C++上的多个继承上下文上使用特定基类中的运算符
- 如何通过带有指向基类的指针的删除运算符释放内存
- 无法在赋值运算符中访问基类的受保护方法
- 如何在抽象基类中实现运算符+
- 将多态性与运算符 + 重载模板化类结合使用.如何实现基类?
- 从参数包中派生的调用基类运算符 =
- 三元运算符隐式强制转换为基类
- 隐藏的成员变量不应在仅允许const访问的基类中突变,以便保留分配运算符
- 为什么不能从派生类调用基类运算符?
- 移动构造函数和移动分配. 基类中的运算符
- 是否可以在基类中删除复制和移动构造函数/分配运算符
- 如何使用继承(抽象基类)实现移动构造函数和移动赋值运算符
- 流运算符和多态基类列表