C++助教篇5_Week3不完全知识点总结
Posted xioacd99
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++助教篇5_Week3不完全知识点总结相关的知识,希望对你有一定的参考价值。
cout格式化输出
利用setf/unsetf or flag来设置cout的格式,前者是在当前状态下追加or删除指定格式,后者是重新设置一个新的格式。如
cout.setf(ios::right); //右对齐
下面从常见格式、对齐与占宽、进制与+/-号、浮点数格式设置来介绍cout格式化输出
常见格式
ios::dec 以10进制表示整数
ios::hex 以16进制表示整数
ios::oct 以8进制表示整数
ios::showbase 为整数添加一个表示其进制的前缀
ios::internal 在符号位和数值的中间插入需要数量的填充字符以使串两端对齐
ios::left 在串的末尾插入填充字符以使串居左对齐
ios::right 在串的前面插入填充字符以使串居右对齐
ios::boolalpha 将bool类型的值以true或flase表示,而不是1或0
ios::fixed 将符点数按照普通定点格式处理(非科学计数法)
ios::scientific 将符点数按照科学计数法处理(带指数域)
ios::showpoint 在浮点数表示的小数中强制插入小数点(默认情况是浮点数表示的整数不显示小数点)
ios::showpos 强制在正数前添加+号
ios::skipws 忽略前导的空格(主要用于输入流,如cin)
ios::unitbuf 在插入(每次输出)操作后清空缓存
ios::uppercase 强制大写字母
setf有两种形式
- 一个参数的,如
cout.setf(ios::right);
可以设置为指定的格式(设置为右对齐) - 两个参数的,如
cout.setf(ios::right,ios::adjustfield);
可以取消原来的一种格式,设置一种新的格式(取消其他对齐,设置为右对齐) - 同属
一个参数
的,但是可以设置多种格式,需要通过|
来组合格式,如cout.setf(ios::right | ios::hex);
(设置为16进制右对齐)
但是,通过格式控制输出不能满足多种格式的要求,在这种情况下,我们可以使用STL提供的<iomanio>
来实现。<iomanip>
提供了如setioflags
,setbase
,setfill
,setw
,setprecision
来方便控制格式
下面通过代码一个个说明其用途(请运行代码查看效果)
对齐与占宽
// endl是flush buffer的newline,'\\n' not ...
cout.flags(ios::left); // ios::left左对齐,设置格式
cout << setw(20) << -123.456 << "hello" << endl; // setw()是设置宽度
// equal to cout << left << setw(20) << -123.456 << "hello" << endl;
// 一次性,更方便
cout.flags(ios::internal); // ios::interal两端对齐
cout << setw(20) << -123.456 << "hello" << endl;
// equal to cout << interal << setw(20) << -123.456 << "hello" << endl;
cout.flags(ios::right); // ios::right右对齐
cout << setfill('*') << setw(20) << -123.456 << "hello" << endl;
// setw()默认使用空格填充,可以通过setfill()来自定义填充字符,一旦更改,除非重新设置,否则保持不变
// equal to cout << right << setw(20) << -123.456 << "hello" << endl;
进制与+
,-
号
cout.setf(ios::showpos | ios::uppercase); //整数显示+,进制有字母的大写
cout.setf(ios::hex); // 16进制的格式输出
cout << 123456 << endl;
// equal to cout << hex << 123456 << endl;
cout.setf(ios::dec); // 10进制的格式输出
cout << 123456 << endl;
// equal to cout << dec << 123456 << endl;
cout.setf(ios::oct); // 8 进制的格式输出
cout << 123456 << endl;
// equal to cout << oct << 123456 << endl;
cout.setf(ios::showbase); //显示进制的前缀
cout << hex << 123456 << endl;
cout << dec << 123456 << endl;
cout << oct << 123456 << endl;
// equal to cout << showbase << hex << 123456 << dec << 123456 << oct << 12346 << endl;
cout.unsetf(ios::showbase); //取消显示进制的前缀
cout << hex << 123456 << endl;
cout << dec << 123456 << endl;
cout << oct << 123456 << endl;
// equal to cout << noshowbase << hex << 123456 << dec << 123456 << oct << 12346 << endl;
cout.unsetf(ios::showpos | ios::uppercase); //取消前面设置的格式
浮点数格式设置
cout.setf(ios::fixed); //四舍五入非科学表示法
cout << setprecision(2) << 123.456 << endl;
// equal to cout << fixed << setprecision(2) << 123.456 << endl;
cout.setf(ios::scientific | ios::floatfield); //四舍五入科学表示法
cout << setprecision(2) << 123.456 << endl;
// equal to cout << scientific << setprecision(2) << 123.456 << endl;
但是,C/C++的格式化输出还是使用printf更方便,代码也更简洁易读
const
const的应用(共享数据保护的一种方式)
const修饰的数据类型是指常类型,常类型的变量或对象的值不能被更新。即const限定一个变量不允许被改变,产生静态作用。使用const在一定程度上可以提高程序的安全性和可靠性。
-
常数据成员变量
常数据成员变量允许在构造函数中初始化,但不能在函数体内初始化,只能在初始化列表中初始化。
-
常成员函数
-
声明:<类型标识符>函数名(形参列表)const;
-
说明:
- const是函数类型的一部分,在实现部分也要带上该关键字;
- const关键字可以用于对重载函数的区分;
- 常成员函数不能修改类的成员变量,也不可以调用类中没有用const修饰的成员函数,只能调用常成员函数,但是可以被其他成员函数调用;
- 特别地:常对象只能访问类中const成员函数(除了系统自动调用的隐含构造函数以及析构函数)
-
常引用:被引用的对象不能被更新。如果想要使用类的私有成员,又想保证私有成员值的安全性(即私有成员的数值不被改变)的时候,可以使用常引用。
const 类型标识符 &引用名;
-
常对象:用const修饰的对象。
const 类名 对象名;
常对象只能调用常成员函数,必须进行初始化。
-
临时变量不能作为非const的引用参数
const的作用
- 欲阻止一个变量被改变,可以使用const关键字。在定义该const变量时,通常需要对它进行初始化,因为以后就没有机会再去改变它了;
- 对指针来说,可以指定指针本身为const,也可以指定指针所指的数据为const,或二者同时指定为const;
- 在一个函数声明中,const可以修饰形参,表明它是一个输入参数,在函数内部不能改变其值;
- 对于类的成员函数,若指定其为const类型,则表明其是一个常函数,不能修改类的成员变量;
- 对于类的成员函数,有时候必须指定其返回值为const类型,以使得其返回值不为“左值”。
- 函数参数的const是告诉函数体不允许修改参数
- 函数末尾的const是告诉函数体不允许修改本类的数据成员
其他需要注意的地方
-
如果不想让编译器察觉到对 const 的操作,可以在 const 前面加上 volatile 关键字。Volatile 关键字跟 const 对应相反,是易变的,容易改变的意思。所以不会被编译器优化,编译器也就不会改变对 a 变量的操作。
-
当有个成员函数想修改对象中的某一个成员时,这时我们可以使用 mutable 关键字修饰这个成员,mutable 的意思也是易变的,容易改变的意思,被 mutable 关键字修饰的成员可以处于不断变化中。
-
C++ const引用、临时变量与引用参数:如果实参与引用参数不匹配,C++将生成临时变量。如果引用参数是const,则编译器在下面两种情况下生成临时变量:
-
实参类型是正确的,但不是左值
-
实参类型不正确,但可以转换为正确的类型
左值参数是可被引用的数据对象,例如,变量、数组元素、结构成员、引用和被解除引用的指针都是左值,非左值包括字面常量和包含多项式的表达式
-
-
从c++中临时变量不能作为非const的引用参数:解释不是临时变量是常量不允许change,而是C++的语义限制。
下面的代码中临时变量(a+b)的val被赋值成了c的val(请运行代码查看)
#include <iostream>
using namespace std;
class TestClass
friend TestClass operator+(const TestClass &left, const TestClass &right);
friend ostream &operator<<(ostream &os, const TestClass &obj);
public:
TestClass() = default;
TestClass(int x) : val(x)
private:
int val;
;
TestClass operator+(const TestClass &left, const TestClass &right)
return TestClass(left.val + right.val);
ostream &operator<<(ostream &os, const TestClass &obj)
os << obj.val;
return os;
int main(int argc, const char **argv)
TestClass a(2), b(3), c(4);
cout << (a + b) << endl;
cout << ((a + b) = c) << endl; //临时对象作为左值
system("pause");
return 0;
应尽可能使用const
-
使用cosnt可以避免无意总修改数据的编程错误
-
使用const使函数能够处理const和非const实参,否则将只能接受非const数据
-
使用const引用使函数能够正确生成并使用临时变量
类作为函数的返回值
当类中成员函数的参数不止一个,且需要同时作为返回值返回时,可用类的形式返回,且在定义返回值类型的时候,返回值类型名应与类名相同
友元函数
类的友元函数是定义在类外部,但有权访问类的所有私有(private)成员和保护(protected)成员。A是B的友元不代表B是A的友元。
友元可以是一个函数,该函数被称为友元函数;友元也可以是一个类,该类被称为友元类,在这种情况下,整个类及其所有成员都是友元。
如果要声明函数为一个类的友元,需要在类定义中该函数原型前使用关键字 friend 进行声明
因为友元函数没有this指针,则参数要有三种情况:
-
要访问非static成员时,需要对象做参数。
-
要访问static成员或全局变量时,则不需要对象做参数。
-
如果做参数的对象是全局对象,则不需要对象做参数.可以直接调用友元函数,不需要通过对象或指针。
注意:友元是C++提供的一种破坏数据封装和数据隐藏的机制,为了确保数据的完整性,每次使用友元函数时最好检查一下友元函数是否会改变private或protected内变量的值。
运算符重载
运算符重载是一种形式的C++多态。其格式operator符号(参数)。例如,operator+()重载为运算符"+“的重载,operator*()为运算符”*“的重载。op必须是有效的C++运算符,不能虚构一个新的符号。一般而言,四则运算的重载函数返回类型仍为给定类(如复数类加法重载运算,返回类型仍是复数类,所以在main函数中可以实现z1=z2+z3的操作),”==""!="返回int。
需要注意的是:C++规定:“=”、“[ ]”、“( )”、“->” 这四个运算符只能被重载为类的非静态成员函数,而不能被重载为友元函数,这是需要特殊记忆的。
运算符重载是对已有的运算符赋予多重含义。C++中预定义的运算符其运算对象只能是基本数据类型,而不适用于用户自定义类型(如类)。
定义一个重载运算符的函数,在需要执行被重载的运算符时,把指定的运算表达式转化为对运算符函数的调用(系统自动调用)。也就是说,运算符重载是通过定义函数实现的。运算符重载实质上是函数的重载。编译系统对重载运算符的选择,遵循函数重载的选择原则(根据实参的类型来确定需要调用的函数)。
重载运算符的规则如下:
-
C++不允许用户自己定义新的运算符,只能对已有的C++运算符进行重载。
-
C++并非所有运算符都能重载,有一些运算符不能重载。(已于下表给出)
-
重载不能改变运算符运算对象的个数。
-
重载不能改变运算符的优先级和结合性。
-
重载运算符的函数不能有默认参数。
-
重载的运算符必须和用户定义的自定义类型的对象一起使用,至少有一个应为类对象。
注:用成员方式重载二元运算符时, 只需要一个右操作参数, 另一个左操作参数由this指针传入,所以,像TestClass::operator+(TestClass&, TestClass&)
都要改成TestClass::operator+(TestClass&)
第一个参数默认由左操作数的this指针自动传入到函数中去的。因此,如果左操作数不是自定义的类的对象,而是int型等其他类型时,不可用成员方式重载,而应用友元函数重载,这样左操作数的类型就没有限制了。下面是可重载的运算符列表:
双目算术运算符 | + (加),-(减),*(乘),/(除),% (取模) |
---|---|
关系运算符 | ==(等于),!= (不等于),< (小于),> (大于>,<=(小于等于),>=(大于等于) |
逻辑运算符 | ||(逻辑或),&&(逻辑与),!(逻辑非) |
单目运算符 | + (正),-(负),*(指针),&(取地址) |
自增自减运算符 | ++(自增),–(自减) |
位运算符 | | (按位或),& (按位与),~(按位取反),^(按位异或),,<< (左移),>>(右移) |
赋值运算符 | =, +=, -=, *=, /= , % = , &=, |=, ^=, <<=, >>= |
空间申请与释放 | new, delete, new[ ] , delete[] |
其他运算符 | ()(函数调用),->(成员访问),,(逗号),[](下标) |
下面是不可重载的运算符列表:
.
:成员访问运算符.
,->
:成员指针访问运算符::
:域运算符sizeof
:长度运算符?
:条件运算符#
: 预处理符号
(单目运算符是只对一个变量进行操作的运算符,双目运算符是对两个变量进行操作的运算符…)
流运算符重载
可以对<<
,>>
运算符进行重载。
cout是一个ostream对象,能够识别所有的C++基本类型,这是因为对于每种基本类型,ostream类声明中都包含了相应的重载的operator<<()定义。所以,同样的,它也可以对自己规定的类型进行定义。如
ostream& TestClass::operator<<(ostream& os, const TestClass& obj)
istream& TestClass::operator>>(istream& in, TestClass& obj)
以上是关于C++助教篇5_Week3不完全知识点总结的主要内容,如果未能解决你的问题,请参考以下文章