左移运算符重载如下:
#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行为。