【C++】关于左移运算符<<重载、cout、endl的思考总结

左移运算符重载如下:

#include<iostream>
#include"main.h"
using namespace std;
void operator<<(ostream &out,Maker &m){
	out<<m.id<<" "<<m.age<<endl;
}
int main(){
	Maker m(12,10);
	cout<<m;
	system("pause");
	return 0;
}

为啥重载函数的ostream的参数必须是引用?

因为不引用的话,相当于传值,也就是要拷贝一份cout对象,但是ostream里面的拷贝构造函数是protected的,无法拷贝。

如何实现连续地输出cout<<m<<endl;?

需要在运算符重载的时候返回cout的引用。

#include<iostream>
#include"main.h"
using namespace std;
ostream& operator<<(ostream &out,Maker &m){
	out<<m.id<<" "<<m.age<<endl;
}
int main(){
	Maker m(12,10);
	cout<<m;
	system("pause");
	return 0;
}

endl本质是啥?和’\n’有什么不同?

在c++的源码中,endl就是一个内联函数,完成换行\n和刷新缓冲区的功能,源码截图如下:
在这里插入图片描述

为什么endl作为一个内联函数可以被用在<<的右边?

源码如下:
在这里插入图片描述
依然是在ostream中写的成员函数实现<<运算符重载,这里面的*_Pfn是函数指针,当我们传递endl给<<的时候,endl作为函数名也表示函数地址,所以根据这里的重载运算符,可以实现cout<<endl;调用endl这个内联函数。

总结

实际上cout作为ostream的对象完成c++中的输出功能,都是在ostream中进行运算符重载实现的。
在这里插入图片描述

关于ostream是否为单例模式

根据ostream对构造函数的定义,只有一个带参数的构造函数是public的:

public:
explicit
      basic_ostream(__streambuf_type* __sb)
      { this->init(__sb); }

通过这个构造函数可以再构造一个ostream对象:

#include <iostream>
#include <fstream>

using namespace std;

int main()
{
    filebuf buf;//streambuf类型的构造函数是保护类型,filebuf是其子类。
    if ( buf.open("/proc/self/fd/1", ios::out) == nullptr )
    {
        cerr << "stdout open failed" << endl;
        return -1;
    }
    ostream out(&buf);
    return 0;
}

可知ostream并不是单例模式。

至于ostream的拷贝构造函数和赋值运算符重载函数都无法被调用。

C++11版本中对这两个函数直接delete:

protected:
      basic_ostream()
      { this->init(0); }

#if __cplusplus >= 201103L
      // Non-standard constructor that does not call init()
      basic_ostream(basic_iostream<_CharT, _Traits>&) { }

      basic_ostream(const basic_ostream&) = delete;

      basic_ostream(basic_ostream&& __rhs)
      : __ios_type()
      { __ios_type::move(__rhs); }

      // 27.7.3.3 Assign/swap

      basic_ostream& operator=(const basic_ostream&) = delete;

      basic_ostream&
      operator=(basic_ostream&& __rhs)
      {
    swap(__rhs);
    return *this;
      }

C++98可以用private继承boost::noncopyable达到同样的目的,在《Effective C++ 3rd》的条款06中有几句话:

可以将copy构造函数或copy assignment操作符【注:赋值运算符】声明为private以阻止编译器暗自创建其专属【注:默认】版本,同时阻止人们调用它。


一般而言这个做法并不绝对安全,因为成员函数和友元函数还是可以调用(这两个)private函数。如果不去定义它们,那么如果某些人不慎调用任何一个,会获得一个连接错误(linkage error)。


“将成员函数生命为private而且故意不实现它们”这一伎俩是如此为大家接受,因而被用在C++ iostream程序库中阻止copying行为【注:copying行为即调用拷贝构造函数和调用赋值运算符重载函数】


将连接器错误移至编译器是可能的,只要将copy构造函数和copy assignment操作符声明为private就可以办到,但不是在自身这个类中,而在一个专门为了阻止copying动作而设计的base class 内。

即使用noncopyable基类可以安全有效避免copying行为。

  • 7
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值