• C++ Primer Plus第五版笔记(p51-100)


    45
    在这里插入图片描述

    46 常量指针必须初始化
    47 一条语句可以定义出不同类型的变量 int i=10, *p=&i,&r =i;
    48 应该是int p 而不是int p
    49 **表示指向指针的指针 p52
    50 指针是对象,所以存在对于指针的引用
    int *p;
    int *&r=p;

    51 在默认状态下 ,const对象只是在文件内部有效
    52 只在一个文件中定义const 而在其他多个文件中声明并使用它:
    唯一的解决办法是 对于const变量不管是声明还是定义都添加 extern 关键字,这样只需要定义一次就够了
    file_1.cc定义并初始化一个常量: extern const int bufsize = fcn();
    file_1.h头文件:extern const int buffSize ;//与file_1.cc中定义的buffSize是同一个

    53 const 的引用 (对常量的引用) 不能修改他所绑定的对象
    const int ci=1024;
    const int &r1=ci;

    54 常量可以引用常量和非常量,非常量只能引用非常量
    55 初始化常量引用时允许用任意的表达式作为初始值 p55
    56 double dval =3.14;
    const int &ri=dval;

    这里编译器创建了一个临时量对象
    const int temp=dval; //由双精度浮点数生成一个临时的整型常量
    const int &ri=temp; //让ri绑定这个临时常量
    而非常量无法跨类引用!!

    57 int i=42;
    const int &r2 =i; //r2绑定对象i,但是不允许通过r2修改i的值
    (常量引用非常量)

    58 允许令一个指向常量的指针指向非常量
    double dval =3.14;
    const double *cptr =&dval;(指向常量的指针不能通过cptr改变对象的值)
    59 const(指向常量对象) double *const(常量指针) pip =& pi(z指向常量对象的常量指针) p56

    60 顶层const:指针本身是个常量 (不允许改变指针pi的值(地址))
    底层const:指针所指向的对象是个常量 (允许改变指针pi的值(地址))

    声明引用&的const都是底层const (所引用的对象是个常量)

    const int ci =42; 顶层const (不允许改变ci的值)

    61 考入和考出的对象必须拥有相同的底层const资格,或者两个对象的数据类型必须能够转换,一般来说,非常量可以转换为常量

    62 常量拷贝给非常量是可以的,但是不能非常量引用常量

    63 指向常量的指针可以指向指向非常量的指针,但是反过来不行

    64
    在这里插入图片描述

    65 允许将变量声明为constexpr 类型以便由编译器来验证变量的值是否是一个常量表达式,声明为constexpr的值一定是一个常量,而且必须由常量表达式初始化 (C++11特性)

    66 字面值类型: 算数类型,引用,指针

    67 定义于函数体内的变量没有固定地址,不能使用constexpr ;而函数体外部的对象定义时的地址固定不变,可以使用constexpr
    68
    如果constexpr声明中如果定义了一个指针,那么constexpr只对指针有效,对于其所指向的对象无关
    constexpr int * q =nullptr 相等于 int const * q 表示q是一个指向整数的常量指针(顶层const)

    constexpr const int *p= &i; 顶层 底层

    69 类型别名 typedef /using 变量别名是&

    typedef double wages; //wages 是double的一个别名
    typedef wages base , *p; //base是 double的另一个别名 p是double *的别名
    using SI= int; //SI是int 的别名

    这里注意 typedef char * pstring ;
    const pstring cstr=0; cstr是指向char的常量指针
    上面这句话不等于 const char * cstr =0; p61
    这种理解是错误的 ,用到了pstring 其基本数据类型是指针, 而用char *重写过后,数据类型就变成了char ,*成为了声明符的一部分

    70 让编译器分析表达式类型 auto (C++11 新特性)

    使用auto 时一条语句只能有一个基本数据类型
    auto i = 0 , *p=&i; //i为整数,p为整型指针

    71 使用引用其实是在使用引用的对象,当引用参与初始化时,真正参与初始化的是引用对象的值
    72 auto一般会忽略顶层const 而底层const 会被保留下来
    73 auto 对常量对象取地址是一种底层const
    74 不能为非常量引用绑定字面值,可以为常量引用绑定字面值

    75 设置一个类型为 auto的引用时,初始值中的顶层常量属性任然保留。和往常一样,如果我们给初始值绑定一个引用,则此时的常量就不是顶层常量了。

    76
    在这里插入图片描述在这里插入图片描述在这里插入图片描述

    77 使用decltype返回类型(c++11特性) 如果decltype使用的表达式是一个变量,那么decltype返回该变量的类型(包括顶层const以及引用在内)
    p63
    decltype(cj) x=0;

    78 decltype®的结果是引用类型,如果想让结果是r所指的类型,那么可以把r作为表达式的一部分,如r+0,显然这个表达式的结果是一个具体值而不是引用
    如果是解引用操作,那么decltype将得到引用类型 因此,decltype(*p)的结果类型是int &而不是int

    79 decltype((variable))双层括号的结果永远是引用,而 devcltype(variable)的结果只有当变量本身就是一个引用的时候才是引用

    80 类体后面可以紧跟变量名以示对该类型对象的定义,所以分号不能少
    81 对象的定义 和类的定义 最好不要放在一起
    82
    在这里插入图片描述

    83 2.41 习题复习

    #include 
    #include 
       
    using namespace std;
    class Sales_data {
    friend std:: istream & operator >> (std::istream& , Sales_data&);
    friend std:: ostream& operator <<(std::ostream&, const Sales_data&);
    friend bool operator <(const Sales_data&, const Sales_data&);
    friend bool operator==(const Sales_data&, const Sales_data&);
    public:
    	Sales_data() = default;
    	Sales_data(const std::string& book) :bookNo(book) {}
    	Sales_data(std::istream& is) { is >> *this; }
    public:
    	Sales_data& operator +=(const Sales_data&);
    	std::string isbn() const { return bookNo; }
    private:
    	std::string bookNo;
    	unsigned units_sold = 0;
    	double sellingprice = 0;
    	double saleprice = 0.0;
    	double discount = 0.0;
    };
    inline bool compareIsbn(const Sales_data& lhs, const Sales_data& rhs)
    {
    	return lhs.isbn() == rhs.isbn();
    }
    
    Sales_data operator +(const Sales_data&, const Sales_data&);
    
    inline bool operator == (const Sales_data& lhs, const Sales_data& rhs)
    {
    	return lhs.units_sold == rhs.units_sold && lhs.sellingprice == rhs.sellingprice && lhs.saleprice == rhs.saleprice && lhs.isbn() == rhs.isbn();
    }
    
    inline bool operator !=(const Sales_data& lhs, const Sales_data& rhs)
    {
    	return !(lhs == rhs);
    }
    
    Sales_data& Sales_data::operator+=(const Sales_data& rhs)
    {
    	units_sold += rhs.units_sold;
    	saleprice = (rhs.saleprice * rhs.units_sold + saleprice * units_sold) / (rhs.units_sold + units_sold);
    	if (sellingprice != 0)
    	{
    		discount = saleprice / sellingprice;
    		return *this;
    	}
    }
    
    Sales_data operator +(const Sales_data& lhs, const Sales_data& rhs)
    {
    	Sales_data ret(lhs);
    	ret += rhs;
    	return ret;
    }
    
    std::istream& operator>>(std::istream& in, Sales_data& s)
    {
    	in >> s.bookNo >> s.units_sold >> s.sellingprice >> s.saleprice;
    	if (in && s.sellingprice != 0)
    	{
    		s.discount = s.saleprice / s.sellingprice;
    	}
    	else
    	{
    		s = Sales_data();
    	}
    	return in;
    }
    std:: ostream& operator <<(std::ostream& out, const Sales_data& s)
    {
    	out << s.isbn() << " " << s.units_sold << " " << s.sellingprice << " " << s.saleprice << " " << s.discount;
    	return out;
    }
    
    int main()
    {
    	Sales_data book;
    	cout << "请输入销售记录" << endl;
    	while (cin >> book) {
    		cout << "ISBN,售出本书,原始价格,实售价格,折扣为" << book << endl;
    	}
    	Sales_data trans1, trans2;
    	cout << "请输入两条ISBN相同的销售记录" << endl;
    	cin >> trans1 >> trans2;
    	if (compareIsbn(trans1, trans2))
    	{
    		cout << "汇总信息:ISBN,售出本书,原始价格,实售价格,折扣为" << trans1 + trans2 << endl;
    	}
    	else
    	{
    		cout << "两条销售记录的ISBN不同" << endl;
    	}
    	Sales_data total, trans;
    	cout << "请输入几条ISBN相同的销售记录" << endl;
    	if (cin >> total) {
    		while (cin >> trans)
    		{
    			if (compareIsbn(total, trans))
    				total = total + trans;
    			else
    				cout << "当前书籍ISBN不同" << endl;
    			    break;
    		}
    		cout << "有效汇总信息:ISBN,售出本数,原始价格,实售价格,折扣为" << total << endl;
    	}
    	else
    	{
    		std::cout << "没有数据" << endl;
    		return -1;
    	}
    	int num = 1;
    	cout << "请输入若干销售记录:" << endl;
    	if (cin >> trans1) {
    		while (cin >> trans2)
    		{
    			if (compareIsbn(trans1, trans2))
    				num++;
    			else
    			{
    				cout << trans1.isbn() << "共有" << num << "条销售记录" << endl;
    				trans1 = trans2;
    				num = 1;
    			}
    			cout << trans1.isbn() << "共有" << num << "条销售记录" << endl;
    		}
    	}
    	else
    	{
    		cout << "没有数据" << endl;
    		return -1;
    	}
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136

    84 确保头文件多次包含还是能安全工作的常用技术是预处理器
    预处理功能(头文件保护符)
    #ifdef 当且仅当变量已定义为真
    #ifndef 当且仅当变量未定义为真,一旦检查结果为真,则执行后续操作指导遇到#endif指令为止
    85
    如果后面再包含sales_data.h 那么#ifndef的检查结果为假,那么编译器将会忽略#ifndef到#endif 之间的部分

    86 基于头文件中类的名字构建保护符的名字,以确保其唯一性,一般把预处理变量的名字全部大写

    87 头文件即使还没有包含在任何其他头文件中,也应该设置保护符

    88 const 对象一旦定义就无法再赋新值,所以必须初始化

    89 #ifndef #define #endif

    90 两种重要的标准库类型:string vector
    91 用using 声明不需要后面专门使用前缀
    using namespace::name;
    每一个名字都需要单独的声明

    92 头文件不应该包含using 声明,如果这样,每个使用该头文件的文件都会有这个声明,会产生一些不必要的名字冲突

    93 六种初始化string 的方式

    94 拷贝初始化和直接初始化:没有等号的是直接初始化

    95 string的操作 p77

    96 cin>>s //将string对象读入s,遇到空白停止
    97 string 连续输入输出
    98 使用getline函数读一行数,直到遇到换行符为止,

    在这里插入图片描述

    99 size_type是size函数返回的类型
    s.size()

    100 如果一条表达式中已经有了size()函数就不要使用int 了,这样可以避免混用int 和 unsigned 可能带来的问题
    101 字符串之间比大小,先是比长度再是比第一对相异字符
    102 当字符字面值和字符串字面值相加时,必须保证加号两边的运算对象其中一个是string类型(字符串字面值不是string对象)

    103 string的输入运算符自动忽略开头的空白,从第一个真正的字符开始读起,知道遇到下一处空白为止
    getline从输入流中读取数据,知道遇到换行符位置,换行符也被读进去,但是不会储存在最后的字符串中

    104 cctype头文件 #include 函数和定义 p82
    105 基于范围的for语句
    想要改变对象中的字符值,必须把循环变量定义成引用类型
    106 使用下标时,将下标的类型设为string::size_type 这个是个无符号数,所以不会小于0,只要让其小于size()就可以了

    107 vector 是一个类模板 而 非类型
    vector a c++11特性 后面要空一格
    其中每个元素都是vector的对象

    108 vector 初始化 对象 p88
    109 push_back函数 p90
    运用push_back给vector对象添加新元素

    110 vector对象的高效增长 先定义一个空的vector对象,再在运行时向其中添加具体值(动态添加元素)

    111 vector操作 p91

    112 vector ::size_type 正确(必须指定它是由哪种类型定义的)
    113 不是所有的vector对象都能互相比较
    114 vector对象不能直接通过下表添加元素,必须使用push_back,下标运算只能用于访问已经存在的元素,而不能用来添加元素

    在这里插入图片描述

    115 遍历vector对象不同元素的每个字符

    116 练习3.20
    117 string 和 vector都支持迭代器(除了下标运算可以访问string对象的字符或vector对象的元素,也可以使用迭代器)
    118 begin是负责返回指向第一个元素的迭代器
    end是负责范围指向容器尾部元素的下一个位置(尾后迭代器)
    如果容器为空begin和end同时返回同一个迭代器,都是尾后迭代器

    119 如果两个迭代器指向的元素都是同一个容器的尾后迭代器,那么他们相等;否则不等
    120 标准容器迭代器的运算符 p96
    121 可以通过解引用迭代器来获得它所指示的元素
    122 const_iterator iterator 是可以表示迭代器的类型,两者区别是后者可读可写,前者不可写(每个容器类定义了一个名为iterator的类型,该类型支持迭代器概念所规定的一套操作)

    123 cbegin cend 是c++11新特性为了得到const_iterator类型的返回值(无论vector是否是常量)
    124 (*it).empty() 解引用调用迭代器所指向类的成员函数 it->empty()也行
    125 不能在范围for循环中向vector对象添加元素,改变vector容量的操作会使得vector对象的迭代器失效
    凡是使用迭代器的循环体,都不要像迭代器所属的容器添加元素!

    126 迭代器运算 p99-100
    difference_type是带符号整型数,是两个迭代器距离的返回类型

    127 二分搜索法 p100

  • 相关阅读:
    20221120
    Java_笔记_继承_虚方法表_成员变量方法构造_thisSuper
    Java简历与面试
    Springboot中EasyExcel导出及校验后导入前后台功能实现
    主成分分析(Principal Component Analysis, PCA)
    Python四大数据结构整理
    优化 cesium 界面广告牌(billboard)数据量大于 10w +时,地图加载缓慢、卡顿、加载完成后浏览器严重卡顿甚至崩溃问题
    【6】Spring Boot 3 集成组件:knift4j+springdoc+swagger3
    Python攻防-AndroidMainfest数据自动化解析
    L82.linux命令每日一练 -- 第11章 Linux系统管理命令 -- dmidecode和lspci
  • 原文地址:https://blog.csdn.net/zhangyuanbonj/article/details/128066058