C++ primer总结

C++笔记:https://www.cnblogs.com/xsqblogs/p/14681536.html

我现在基础已经还行,可以直接看C++11部分,如果遇到不懂的再看其他

可以用少量字总结的就总结一下,如果不行,就只写一下有什么知识

练习答案:https://github.com/applenob/Cpp_Primer_Practice

1.main()函数return的是0,则表示成功;非零表示各种错误类型

不同编译器规定c++源文件的后缀不同,可能是cc,cpp,cp等

UNIX可执行文件后缀为.out,可以没有后缀;windows可执行文件后缀为.exe

ubuntu中直接输入a.out是无法找到可执行文件,需要执行./a.out通过“./”告诉系统可执行文件所在目录。

在命令行中运行完可执行文件后,可以使用echo输出main函数返回的值

2.cin和cout是两个对象,<<是一个运算符。

cerr和clog也是两个输出对象,分别用于输出错误和日志

程序员常常在调试时添加打印语句。这类语句应该保证“一直”刷新流,即cout都应该以<<std::endl结尾。否则,如果程序崩溃,输出可能还留在缓冲区中,此时我们以为某位置没有输出,其实是输出了,只是留在了缓冲区中。这就会导致导致关于程序崩溃位置的错误推断。

<<可以输出不同类型数据,是因为定义了不同版本的<<运算符来处理不同类型的数据。

3.while(std::cin>>value)中std::cin>>value返回的是一个std::cin对象,当对象是文件结束符(或输入错误)时while循环结束。

文件结束符:windows下为ctrl+z或Enter,linux(或MAC os x)下为ctrl+d。

常见错误类型:syntax error(如忘写分号)、type error(int型被字符串进行赋值)、declaration error(名字拼写错误、忘写std::)

修改一部分代码就重新编译调试一次,因为后面很多错误可能只是由前面修改的错误引起的。

类就是一种自定义的数据类型

标准库的头文件使用#include<>,非标准库的头文件(自己写的头文件)使用include""。

./test.out <text.txt> text2.txt:代表使用cin的地方从text.txt中读取内容,使用cout的地方将内容输出到text2.txt中

4.空类型(void):当函数不返回任何值时使用空类型作为返回类型。

不同机器上数据类型(又称算术类型)占用的比特不同,但c++规定了各类型的最小尺寸。

wchar:存放扩展字符;char16_t、char32_t:存放Unicode字符

每个地址上可以存放的比特数称为字节,一个字节一般是八个比特;CPU一次性处理的数据大小称为字,64位计算机指的是字的大小为8个字节。

char用signed char或unsigned char来实现,不同的编译器实现的方式不同;所以如果实在必须将char当成整型来用,指明使用的是signed char还是unsigned char。

数值范围int无法表示,一般直接使用long long;浮点运算一般使用double,不使用float。

5.类型转换

类型转换:如char转int——就是将char变量对应的二进制码解读成int。

无符号数赋值超过表示范围时,结果是初始值对无符号类型可表示的数值的个数取模后的余数。给有符号数赋值超过表示范围时,结果为未定义,此时程序可能出现不可预知的风险。

int和无符号数相加时,int变量会被转换成无符号数。如果此时int变量是负数,则直接将此负数对应的二进制补码解读成原码;

无符号相减得到的结果如果是负数:如u2-u1为负数,则u2-u1=u2+(-u1),其中-u1的机器码为补码,这里的补码解读为原码。

for(unsigned u=10;u>=0;- -u)中当u=-1时,u实际为4294967295。及其解决方法。

切勿混用带符号类型和无符号类型进行运算

6.字面值常量

字面值常量:就是告诉你整数、浮点数、字符串等需要怎么表示

八进制:0开头;十六进制:0x或0X开头

默认情况下,十进制字面值是带符号数,八进制和十六进制字面值既可能是带符号的也可能是无符号的。

十进制字面值是利用“int、long、long long”中一个来装载的。具体选的是可容纳此字面值的最小类型来装载。

八进制和十六进制字面值是利用“int、unsigned int、long、unsigned Iong、Iong long和unsigned long long ”中一个来装载的。具体选的是可容纳此字面值的最小类型来装载。

浮点数默认使用double来装载。3.14159E0或3.14159e0中的E0或e0代表乘以10的0次方

我们还可以自己选择利用哪个类型来装载,只需要利用字面值后添加相应的后缀即可,如42ULL代表42这个数用unsigned long long来装载。如果指定的装载类型太小,编译器会自动用其他更大的类型来装

由单引号括起来的一个字符称为char型字面值,双引号括起来的零个或多个字符则构成字符串型字面值。

字符串字面值是由字符数组来装载的,编译器在每个字符串的结尾处添加一一个空字符('\0'), 因此,字符串字
面值的实际长度要比它的内容多1。

多行字符串实际会被当成一行字符串。

给字面值添加前缀来指明用什么类型装在字符或字符串,如L’a’代表用wchar_t装载字符a

7.变量

变量可以当成内置的对象

string在std命名空间中被定义

初始化的含义是创建变量时赋予其一个初始值,而赋值的含义是把对象的当前值擦除,而以一个新值来替代。

列表初始化:int a={0}或int a{0}。如果我们使用列表初始化且初始值存在丢失信息的风险,则编译器将报错(如int a{1.111}中的.111会丢失

函数体外定义的变量对应的机器码会默认初始化为零函数体内定义的变量可能会初始化成没有意义的数或者为未定义
一个未被初始化的内置类型变量的值是未定义的(还有,给有符号数赋值超过表示范围时,结果也为未定义),如果试图拷贝或以其他形式访问此未定义变量将引发错误。这句话没看懂???

为了安全建议初始化每一个内置类型的变量

声明:告诉了程序这个变量的存在,但未申请内存。定义:申请了内存。

声明:在变量前面添加extern,如extern int a;

一个文件如果想使用别处定义的名字则必须包含对那个名字的声明

变量能且只能被定义一次。但是可以被多次声明

函数内部不能声明变量

显式初始化的声明即成为定义。“extern int val = 1; ”为定义

函数的声明是函数头,也可以在函数头左边加上extern。函数声明的形参可以只写类型,而不写形参的名称。

c++中不能使用标识符:不能连续出现两个下划线;不能以下划线紧连大写字母开头;定义在函数体外的标识符不能以下划线开头

变量名一般用小写字母,如index;用户自定义的类名一般以大写字母开头,如Sales_item;标识符由多个单词组成时,单词之间用下划线隔开或除第一个单词外的其他单词都大写。

不用把定义都放在开头,放在使用的地方的附近(注意不要重复定义)

cout<<::reused;表示访问全局变量reused

8.引用就是别名,引用上的任何改变都是对原变量的改变。int &a=b;

引用必须初始化;无法更改绑定对象;引用只能绑定在对象上,不能绑定在字面值上

引用的作用:函数fun(int &a)传入实参a时,不需要复制一份a,而直接传入a本身。函数fun(int a)传入实参a时,需要复制一份a。

指针:存储对象的地址。由于引用不是对象,只是别名,所以没有指向引用的指针。利用取地址符&取引用地址时,取到的是引用指向变量的地址。

无效指针:最常见的是,指针所指的内存单元被释放了,此时指针就变为了无效指针,不遗留任何无效指针总是最好的实践方式。

如果p是个指针,则*p代表访问p所指向对象。

空指针:int *p=nullptr;int *p=0;int *p=NULL;

其中NULL是预处理变量,在预处理阶段会被替换成零

int变量直接赋给指针是错误的操作即使int变量的值恰好等于0也不行

建议所有指针都要进行初始化

指针一般写成这样:int *p,而不写成int* p。再如:int* p1, p2; // p1是指向int的指针,p2是int

指向指针的引用:给指针取别名,如int *&r=p,从右往左读,首先读到&,代表r是一个引用,其余部分代表r是什么类型数据的引用,即int指针的引用

const

const int k=9;定义一个不可改变的常量,k必须在定义的时候就初始化,任何在k上的操作都不可以修改k的值

常量引用(常量的引用):

  • 非常量引用不可以指向一个常量对象;常量引用可以指向一个非常量对象
  • 在初始化常量引用时允许用任意表达式作为初始值,只要该表达式的结果能转换成引用的类型即可,如下:
double dval =1.1;
const int &ri = dval;
// int &ri = dval; // 此语句会出错

const int &ri = dval;未出错的原因:ri绑定的是一个临时常量而不是dval。
int &ri = dval; 出错的原因:ri找不到绑定的对象。为什么普通引用不可以绑定到临时常量上呢?答:因为一般需要修改dval时,才会使用普通引用。所以如果普通引用被绑定在临时变量上了,就不可以修改dval了

const int *ri = dval ;其中dval为int类型,即dval可以不是const int。dval为int类型时,应该和上面一样:ri实际是绑定了一个临时变量

const指针:指针本身为常量。

int *const E=&e;const代表E本身是一个常量,int *代表这个常量是int类型指针。const double *const pip=&pi;const代表pip是一个常量,const double *代表这个常量是double常量类型指针

指针本身是一个常量并不意味着不能通过指针修改其所指对象的值。

顶层const( top-level const)表示本身是个常量,底层const (low-level const)表示指针或引用所指的对象是一个常量。

常量表达式:值不会改变并且在编译过程就能得到计算结果的表达式。如当表达式中含有函数时,计算结果是在运行的时候才能得到。常量表达式在后面会用到。

C++11中判断是否为常量表达式的方法是将表达式赋给constexpr变量。constexpr变量:constexpr int a = A,编译器会验证A是否为常量表达式。

constexpr指针:只能存放地址固定的对象的地址。如一般函数体内的对象(变量)一般不能由constexpr指向(但有例外,例外是啥呢????),函数体内可以。

constexpr const int *p=&i; // p是常量指针,指向整型常量i
constexpr int *p1=&j;// p1是常量指针,指向整数j

10、

取别名:

​ typedef int *p; // p为int *的别名

​ typedef int p; // p为int的别名

​ using SI = Sales_ item; // SI为Sales_ item的别名

​ typedef char *pstring;
​ const pstring cstr = 0; // cstr是指向char的常量指针

​ const char *cstr = 0; // cstr是指向char类型常量的指针

auto item = val1 + val2; // auto推断出val1+val2为类型A,并将item定义成类型A。等号自然是将val1+val2的值,赋给了item。

auto也能在一条语句中声明多个变量以及其注意点

auto a = i; // i是一个引用。auto获取的是i所指对象的类型,而不是获取到引用类型。

auto会忽略顶层const,底层const会被保留下来。

使用auto获取引用类型和顶层const的方法

不能为非常量引用绑定字面值,可以为常量引用绑定字面值。

设置一个类型为auto的引用时,初始值中的顶层常量属性仍然保留。

auto不能确定基本数据类型是什么而导致的错误

decltype:只返回表达式的类型,返回表达式的值(即不用表达式的值进行初始化)

decltype(ci) x=2; \\ 获取ci的类型A,将x定义成类型A并初始化为2;

decltype处理项层const和引用的方式与auto有些许不同。如果decltype使用的表达式是一个变量,则decltype返回该变量的类型(包括顶层const和引用在内):

需要指出的是,引用从来都作为其所指对象的同义词出现,只有用在decltype处是一个例外。

如果decltype使用的表达式不是一个变量时,则decltype返回表达式结果对应的类型【具体见原文】

如果表达式的内容是解引用操作,则decltype将得到引用类型。

切记: decltype ( (variable)) (注意是双层括号)的结果永远是引用,而decltype (variable)结果只有当生variable本身就是一个引用时才是引用。

使用struct自定义数据结构(类)【struct使用方法和class相似,不需要再看了 】

C++11新标准规定,可以为数据成员提供一个类内初始值

头文件的编写

类名一般和头文件名一样

头文件通常包含那些只能被定义一次的实体,如类、const和constexpr变量(

通过#ifndef和文件保护符防止头文件的重复引用。通常文件保护符的名字和类名有关

接下来看第三章

重载:相同函数名,不同形参

重写:子类对父类中相同函数(函数名、形参和返回值都相同)的覆盖

空的形参列表的两种表示:void f();或void f(void);。void f(void)是为了和C语言兼容

void函数不返回任何值。函数的返回类型不能是数组类型或函数类型,但可以是指向数组或函数的指针。

goto语句:goto label;代表跳转到代码label:所在的位置

异常处理

异常处理:throw在try中抛出异常,根据异常的不同选择不同的catch块。

多层函数调用中,出现异常,程序会一层一层的往上寻找对应的catch语句,找不到就终止程序。
catch块中一般进行内存释放等清理操作。
大多数常见的类都是定义在标准库中的,所以调用的时候,都要带std::,如std::runtime_error。
如果异常类型有一个字符串初始值,则what()返回字符串。
具体见原文和链接

函数指针

将函数名替换成(*pf)就生成了一个函数指针pf。
函数名当成一个值使用时,该函数名被当成地址。
函数指针作为形参
函数指针作为返回值

智能指针

智能指针不用自己释放内存,只要没有指针指向内存了,就会自动释放。
shared_ptr允许多个指针指向同一个对象
unique_ptr则“独占”所指向的对象。
标准库还定义了一个名为weak_ ptr的伴随类,它是一种弱引用,指向shared ptr所管理的对象。这三种类型都定义在memory头文件中。
shared_ptr创建出对象,而对象当然有相应的方法可以调用,如返回对象被引用的次数。
make_shared用于动态分配内存并初始化
接下来看404

IO库

cout<<:代表向对象cout写入内容,<<代表写入的意思
三大IO类:

  • iostream针对IO流
  • fstream针对文件
  • sstream针对string类型
    类型ifstream和istringstream都继承自istream。类型ofstream和ostringstream都继承自ostream。所以对istream和ostream进行的操作,对其他两类型也可以。

位运算符

其他:

补码运算:正数为原码本身,负数为原码取反加一

问题:

2.取模运算?答:链接

3.int转无符号数的规则是什么?

4.为什么说初始化和赋值是两个完全不同的操作,是因为一个使用构造函数,另一个使用别的东西吗??

5.constexpr变量的变量到底有什么作用?

6.“2.2.1”中有一个问题?

C++11

constexpr变量

C++11中判断是否为常量表达式的方法是将表达式赋给constexpr变量。constexpr变量:constexpr int a = A,编译器会验证A是否为常量表达式。所以如果你确定A为常量表达式,那么就应该使用constexpr进行定义。

union:一种节省空间的类

union是一种节省空间的类,所以union是一种类,此类不能继承其他类、不能成为基类、不能有虚函数。
union使用的时机:

  • 当多个数据类型要占用同一片内存时
  • 当多个数据类型只取其一时

当需要判断是大端模式还是小端模式时,我们就需要多个数据类型要占用同一片内存:

#include <stdio.h>
void byteorder()
{
	union 
	{
		short value;                            // short占 2 字节
		char union_bytes[ sizeof( short ) ];   // sizeof返回一个对象或者类型所占的内存字节数。char占一个字节
	} test;
	test.value = 0x0102;        // 十六进制,每两位占一个字节
	if (  ( test.union_bytes[ 0 ] == 1 ) && ( test.union_bytes[ 1 ] == 2 ) ) // union_bytes[ 0 ]为低地址,01为高位,故为大端模式
	{
		printf( "big endian\n" );
	}
	else if ( ( test.union_bytes[ 0 ] == 2 ) && ( test.union_bytes[ 1 ] == 1 ) )
	{
		printf( "little endian\n" );
	}
	else
	{
		printf( "unknown...\n" );
	}
}

union中含有定义了构造函数或拷贝控制成员的类A作为成员,此时一般将此union定义为匿名union,并且使用一个额外的类B来管理匿名union,还要在类中定义枚举类型来说明此时union中存储的类型。

  • 类B的析构函数析构时,要判断union的类型是否为类A,如果是,则要调用类A的析构函数
  • union的值改为类A的值时,必须运行类A的构造函数;反之,类A的值改为一个其他值时,必须运行类A的析构函数。上述这两个过程一般是在类B的成员函数中写的。(本节的大部分内容都在讲A的构造和析构问题)
posted @ 2022-07-22 17:21  好人~  阅读(142)  评论(0编辑  收藏  举报