对于C ++插入重载,我们通常会这样做:
ostream& operator<<(ostream& os, X& object){
// operation
return os;
}
我的问题是:为什么必须引用X类型的变量对象?
答案 0 :(得分:3)
我的问题是:为什么必须引用变量 X型对象?
您不需要参考,这不是强制性的。在任何情况下,请考虑到,因为您不打算修改 object ,所以最好写成:
ostream& operator<<(ostream& os, const X& object){
// operation
return os;
}
简单的替代方法是通过写入:
按值传递 objectostream& 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; }
然后,为了让 track 在operator<<()
内工作,C ++将复制该对象。 std::vector
gpsPoints 将透明地复制到另一个向量中,在堆中复制其信息(在开始时分配并在方法结束时解除分配)。但是,此信息由 GpsPoint 组成,对于最坏的情况(取决于其实现),它将意味着遍历所有点并调用其副本构造函数。这不仅浪费时间,也浪费资源(即记忆)。
您可以将它作为const引用传递,它与指针一样高效,并且作为传值可以安全(不允许修改)。
希望这有帮助。
答案 1 :(得分:1)
无需使用 const
引用,您也可以按值传递。两个版本同样运作良好
ostream& operator<<(ostream& os, const X &object);
ostream& operator<<(ostream& os, X object);
const引用的原因通常与其他函数相同:对于(大)对象,复制(即按值传递)比传递引用更昂贵。
另一个原因:const&
即使在没有复制构造函数的情况下也能正常工作。
答案 2 :(得分:0)
好吧,通常我们通过值或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()));
}