IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> c++ primer 笔记 -> 正文阅读

[C++知识库]c++ primer 笔记

c++ primer 学习笔记

变量

列表初始化

变量中有个列表初始化感觉挺重要的,列表初始化是c++11中的新特性,看书有点没看明白,看了两篇文章1文章2感觉还挺清晰的.

那么什么是列表初始化呢?其实就是一种新的初始化方式,适用于各种类型,可以直接在变量名后面加上初始化列表来进行对象的初始化。

vector<string> articles={"a","an","the"};
int a{111};
列表初始化的一些规则

首先说下聚合类型可以进行直接列表初始化,这里需要了解什么是聚合类型:

  1. 类型是一个普通数组,如int[5],char[],double[]等
  2. 类型是一个类,且满足以下条件:
    • 没有用户声明的构造函数
    • 没有用户提供的构造函数(允许显示预置或弃置的构造函数)
    • 没有私有或保护的非静态数据成员
    • 没有基类
    • 没有虚函数
    • 没有{}和=直接初始化的非静态数据成员
    • 没有默认成员初始化器
struct A {
    int a;
    int b;
    int c;
    A(int, int){}
};
int main() {
    A a{1, 2, 3};// error,A有自定义的构造函数,不能列表初始化
}

上述代码类A不是聚合类型,无法进行列表初始化,必须以自定义的构造函数来构造对象。

struct A {
    int a;
    int b;
    virtual void func() {} // 含有虚函数,不是聚合类
};

struct Base {};
struct B : public Base { // 有基类,不是聚合类
      int a;
    int b;
};

struct C {
    int a;
    int b = 10; // 有等号初始化,不是聚合类
};

struct D {
    int a;
    int b;
private:
    int c; // 含有私有的非静态数据成员,不是聚合类
};

struct E {
      int a;
    int b;
    E() : a(0), b(0) {} // 含有默认成员初始化器,不是聚合类
};

上面列举了一些不是聚合类的例子,对于一个聚合类型,使用列表初始化相当于对其中的每个元素分别赋值;对于非聚合类型,需要先自定义一个对应的构造函数,此时列表初始化将调用相应的构造函数。

std::initializer_list

我们平时开发使用STL过程中可能发现它的初始化列表可以是任意长度,大家有没有想过它是怎么实现的呢,答案是std::initializer_list,看下面这段示例代码:

struct CustomVec {
    std::vector<int> data;
    CustomVec(std::initializer_list<int> list) {
        for (auto iter = list.begin(); iter != list.end(); ++iter) {
            data.push_back(*iter);
        }
    }
};

我想通过上面这段代码大家可能已经知道STL是如何实现的任意长度初始化了吧,这个std::initializer_list其实也可以作为函数参数。

注意:std::initializer_list,它可以接收任意长度的初始化列表,但是里面必须是相同类型T,或者都可以转换为T。

类型转换

warning:切勿将带符号类型与无符号类型混用,这样会导致结果产生异常,如a-1,b=1,a*b=-1,当a,b都为有符号int型时,结果是如此,但是当a是无符号类型时,结果就会等于4294967295,所以切勿将有符号类型与无符号类型混用。

auto与decltype

两者均可将一个变量定义成一个表达式的类型,但是有一点不同点需要注意,如果希望推断出的auto类型是一个顶层const,需要明确指出:

const ci = 1;
const auto f = ci;

如果不加const的话,f变量就只是一个int型,并不是一个顶层const。

引用也同理,如果想将结果定义成引用类型的话,需要明确中指出

auto &g = ci;

如果不添加的话,ci是int &类型,定义出的g仍是int类型。

还有一点不同就是decltype的结果类型与表达式的形式密切相关。有一种情况需要特别注意:如果decltype使用的是一个不加括号的变量,则得到的结果就是该变量的类型,如果给表达式加上了一层或者多层括号,编译器就会把它当成是一个表达式。变量是一种可以作为赋值语句左值的特殊表达式,所以这样的decltype就会得到引用类型。

//decltype的表达式如果是加上了括号的变量,结果将是引用
decltype((i)) d;  //错误,d是引用类型,定义时需要初始化
decltype(i) e;   //正确,e是一个未初始化的int变量

预处理器

预处理器概述:

确保头文件被多次调用还能安全正常工作的技术是预处理器,它由C++语言从C语言继承而来,预处理器是在编译之前执行的一段程序,可以部分的改变我们所写的程序,当预处理器看到#include标记时就会用指定头文件的内容代替#include。

C++程序还会使用的一项预处理功能是头文件保护符,头文件保护符依赖于预处理变量。预处理变量有两种状态:已定义和未定义。

#define指令把一个名字设为预处理变量,另外两个指令则分别检查某个指定的预处理变量是否已经被定义。

#ifdef当且仅当变量已被定义时为真,

#ifndef当且仅当变量未被定义时为真,

一但检查结果为真时,则执行后续操作直至遇到#endif指令为止。

使用这些功能可以有效的防止重复包含的发生。

#ifndef SALES_DATA_H
#define SALES_DATA_H
#include<string>
struct Sales_data {
	std::string bookNo;
	unsigned units_sold = 0;
	double revenue = 0.0;
};

#endif

第一次包含Sales_data.h时,#ifndef的检查结果是真,预处理器将顺序执行后面的操作直至#endif处为止,此时SALES_DATA_H的值变为已定义,而且Sakes_data.h也会拷贝到我们的程序中来。后面如果再一次包含Sales_data.h,则#inndef的检查的结果为假,编译器将会忽略#ifndef到#endif之间的部分。

但是在实际开发过程中,直接使用#pragma once就可以了,方便又简洁。

warning:预处理器变量无视c++中关于作用于的规则。

string

getline函数

getline函数的参数是一个输入流和一个string对象,函数从给定的输入流中读入内容,直到遇到换行符为止(注意换行符也读进来了),然后把所读的内容存入到那个string类型中去(注意不存换行符)。和输入运算符一样,getline函数也会返回他的流参数,所以我们也能用getline的结果作为条件

int main()

{
	string line;
	while(getline(cin,line))
		cout<<line<<endl;
	return 0;
}
size()函数

size函数有一点需要注意的是它的返回值并不是int型,而是一个unsigned int型,也就是无符号整型,前面也提到过,有符号类型一定不能和无符号类型混用,所以要切记如果表达式中存在size()函数就一定不要再使用int型了。

不一样的for循环

c++11新标准中提供了一中语句:范围for(range for)语句。这种语句遍历给定序列中的每个元素并对序列中的每个值执行某种操作。其语法形式是:

for(declaration : expression)
	statement

其中,expession部分是一个对象,用于表示一个序列。declaration部分负责定义一个变量,该变量将被用于访问序列中的基本元素。每次迭代,declaration部分的变量都会被初始化为expression部分的下一个元素值。

string str("woshinidie");
for(auto c : str)
    cout<<c<<endl;

//运行结果为 : 
	w
	o
    s
    h
    i
    n
    i
    d
    i
    e
string s("Hello World!!!");
decltype(s.size()) punct_cnt = 0;
for(auto c : s)
    if(ispuntc(c)) //判断是否为标点符号
    	++punt_cnt;
cout << punt_cnt << "个标点符号在" << s << "中" << endl;

//运行结果:3个标点符号在Hello World!!!中

现在已经可以通过范围for对其进行读,那么我们该如何对其进行改的操作呢?很简单,只要在定义declaration时将其定义为引用就可以了。

函数总结:

ispunct(char c)

判断字符c是否为标点符号。

toupper(char c)

将字符c转化为大写。

isspace(char c)

判断是否为空格。

vector

vector支持的操作
v.size()返回v中元素的个数
v.push_back(t)向v的尾端添加一个值为t的元素
v[n]返回v中第n个位置上的元素的引用
v1={a,b,c…}用列表中元素拷贝替换v1中的元素
<, <=, >, >=顾名思义,一字典顺序进行比较
v.empty()如果v不含有任何元素,返回真:否则返回假
  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-10-19 11:41:26  更:2021-10-19 11:42:09 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 3:26:20-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码