为什么必须引用流插入重载中的正确操作数?
Why the right operand in stream insertion overloading have to be reference?
对于C++插入重载,我们通常执行以下操作:
ostream& operator<<(ostream& os, X& object){
// operation
return os;
}
我的问题是:为什么它必须引用 X 类型的变量对象?
我的问题是:为什么它必须引用变量 X型对象?
您不需要参考,这不是强制性的。无论如何,考虑到,由于您不打算修改对象,因此最好将其编写为:
ostream& operator<<(ostream& os, const X& object){
// operation
return os;
}
简单的替代方法是按值传递对象,方法是写入:
ostream& operator<<(ostream& os, X object){
// operation
return os;
}
问题出在哪里?您的程序将继续工作,但其性能将受到影响。将指针传递给对象(这就是引用的最终含义)不如复制整个对象有效。假设X有以下实现,即它实际上是GpsTrack类:
/** A complete track, composed by GpsPoints. */
class GpsTrack {
public:
/** Creates a new, empty track. */
GpsTrack()
{}
/** Adds a new point to the track.
* @param p The new point.
*/
void add(const GpsPoint &p)
{ gpsPoints.push_back( p ); }
/** @return The point at position i. */
const GpsPoint &operator[](int i)
{ return gpsPoints[ i ]; }
/** @return The number of points in the track. */
int size() const
{ return gpsPoints.size(); }
/** @return A textual representation of the track. */
std::string toString() const;
/** Adds support for the << operator. */
friend std::ostream& operator<<(std::ostream& os, const GpsTrack& track)
{ os << track.toString(); return os; }
private:
std::vector<GpsPoint> gpsPoints;
};
为了这个例子,让我们以一台 32 位机器为例。每个GpsPoint包含一对double
,每个 存储 8 个字节,因此总共 16 个字节。如果GpsTrack包含 5000 个点,则结果约为 78KB。这由std::vector
透明地存储在堆中。
假设我们没有上面给出的实现,而是以下实现operator<<()
.
/** Adds support for the << operator. */
friend std::ostream& operator<<(std::ostream& os, GpsTrack track)
{ os << track.toString(); return os; }
然后,为了使该轨道在operator<<()
内工作,C++将复制该对象。std::vector
gpsPoint将被透明地复制到另一个向量中,在堆中复制其信息(在方法的开头分配,在方法结束时解除分配)。但是,此信息由GpsPoint组成,在最坏的情况下(取决于其实现),这意味着运行所有点并调用其复制构造函数。这不仅是浪费时间,也是浪费资源(即内存)。
您可以将其作为 const 引用传递,它与指针一样具有性能,并且与按值传递一样安全(不允许修改)。
希望这有帮助。
无需使用const
引用,也可以按值传递。两个版本同样有效
ostream& operator<<(ostream& os, const X &object);
ostream& operator<<(ostream& os, X object);
const 引用的原因通常与其他函数相同:对于(大)对象,复制(即按值传递)比仅传递引用更昂贵。
另一个原因:即使在没有可用的复制构造函数的情况下,const&
也可以工作。
好吧,通常我们要么通过值传递,要么通过常量引用传递。以下是Microsoft VS2017实现的示例。它通过 const 引用传递字符串,因此我们避免复制并且仍然保证不更改对象。
template<class _Elem,
class _Traits,
class _Alloc> inline
basic_ostream<_Elem, _Traits>& operator<<(
basic_ostream<_Elem, _Traits>& _Ostr,
const basic_string<_Elem, _Traits, _Alloc>& _Str)
{ // insert a string
return (_Insert_string(_Ostr, _Str.data(), _Str.size()));
}
- 我的运算符重载是否有效<<(流插入)左操作数不是 ostream
- CPP 运算符重载操作数位置 [] 与 ==
- c++运算符重载-我实际返回的操作数类型是什么
- C++ 重载:[错误] 与'operator='不匹配(操作数类型为 'String' 和"字符串")
- 运算符重载多个操作数C++
- 重载运算符:使用C++文本时的操作数顺序
- 在重载操作数中使用重载操作数"+" "<<" C++中出现大小写错误
- 重载运算符'<<'的使用不明确(操作数类型'ostream'(也称为"basic_ostream<char>")和"Person")
- 使用运算符重载时,没有运算符"<<"匹配这些操作数
- 为什么必须引用流插入重载中的正确操作数?
- 派生类的重载<<运算符表示操作数无效
- 运算符重载时出错(错误:"运算符<<不匹配(操作数类型为"std::basic_ostream<char>"和"const char [2]")
- 重载二元运算符的右操作数是否可以是基本类型的对象
- 如何修复重载操作数+
- 类型别名和运算符<<使用 ostream_iterator 重载会导致无效操作数
- 重载运算符'>>'的使用不明确(操作数类型'istream'(又名"basic_istream<char>")和"MyIncreEx")
- VC++ SFINAE 给出错误 C2070:"重载函数":操作数大小非法
- 混合数字类操作数重载C++
- 将右值引用作为左操作数重载加法操作符被认为是一种良好的做法
- c++中为一个操作数重载二进制操作符