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

2024-03-14 08:40

本文主要是介绍【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:
explicitbasic_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/swapbasic_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行为。

这篇关于【C++】关于左移运算符<<重载、cout、endl的思考总结的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/807856

相关文章

C++中实现调试日志输出

《C++中实现调试日志输出》在C++编程中,调试日志对于定位问题和优化代码至关重要,本文将介绍几种常用的调试日志输出方法,并教你如何在日志中添加时间戳,希望对大家有所帮助... 目录1. 使用 #ifdef _DEBUG 宏2. 加入时间戳:精确到毫秒3.Windows 和 MFC 中的调试日志方法MFC

Python中实现进度条的多种方法总结

《Python中实现进度条的多种方法总结》在Python编程中,进度条是一个非常有用的功能,它能让用户直观地了解任务的进度,提升用户体验,本文将介绍几种在Python中实现进度条的常用方法,并通过代码... 目录一、简单的打印方式二、使用tqdm库三、使用alive-progress库四、使用progres

深入理解C++ 空类大小

《深入理解C++空类大小》本文主要介绍了C++空类大小,规定空类大小为1字节,主要是为了保证对象的唯一性和可区分性,满足数组元素地址连续的要求,下面就来了解一下... 目录1. 保证对象的唯一性和可区分性2. 满足数组元素地址连续的要求3. 与C++的对象模型和内存管理机制相适配查看类对象内存在C++中,规

Android数据库Room的实际使用过程总结

《Android数据库Room的实际使用过程总结》这篇文章主要给大家介绍了关于Android数据库Room的实际使用过程,详细介绍了如何创建实体类、数据访问对象(DAO)和数据库抽象类,需要的朋友可以... 目录前言一、Room的基本使用1.项目配置2.创建实体类(Entity)3.创建数据访问对象(DAO

在 VSCode 中配置 C++ 开发环境的详细教程

《在VSCode中配置C++开发环境的详细教程》本文详细介绍了如何在VisualStudioCode(VSCode)中配置C++开发环境,包括安装必要的工具、配置编译器、设置调试环境等步骤,通... 目录如何在 VSCode 中配置 C++ 开发环境:详细教程1. 什么是 VSCode?2. 安装 VSCo

Java向kettle8.0传递参数的方式总结

《Java向kettle8.0传递参数的方式总结》介绍了如何在Kettle中传递参数到转换和作业中,包括设置全局properties、使用TransMeta和JobMeta的parameterValu... 目录1.传递参数到转换中2.传递参数到作业中总结1.传递参数到转换中1.1. 通过设置Trans的

C# Task Cancellation使用总结

《C#TaskCancellation使用总结》本文主要介绍了在使用CancellationTokenSource取消任务时的行为,以及如何使用Task的ContinueWith方法来处理任务的延... 目录C# Task Cancellation总结1、调用cancellationTokenSource.

C++11的函数包装器std::function使用示例

《C++11的函数包装器std::function使用示例》C++11引入的std::function是最常用的函数包装器,它可以存储任何可调用对象并提供统一的调用接口,以下是关于函数包装器的详细讲解... 目录一、std::function 的基本用法1. 基本语法二、如何使用 std::function

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;