查看: 116|回复: 0

学过 C++ 的你,不得不知的这 10 条细节!

[复制链接]
发表于 2020-2-19 17:35:58 | 显示全部楼层 |阅读模式
逐日一句英语学习,天天进步一点点:


  • “Action may not always bring happiness; but there is no happiness without action.”
  • 「行动不见得一定带来快乐,但没有行动就没有快乐。」
前言

我在阅读 《Effective C++ (第三版本)》 书时做了不少条记,从中收获了非常多,也明白为什么会书中前言的第一句话会说:

对于书中的「条款」这一词,我更喜欢以「细节」替换,毕竟年轻的我们在打 LOL 或 王者的时,总会说注意细节!细节!细节~ —— 细节也算伴随我们的芳华的字眼
针对书中的前两个章节,我筛选了 10 个 细节(条款)作为了本文的内容,这些细节也相对基础且紧张。
针对这 10 细节我都用较简便的例子来加以阐述,同时也把本文所提及细节中的「小结」总结绘画成了一副思维导图,便于大家的阅读。
温馨提示:本文较长(万字),发起收藏阅读。
后续有时间也会继续分享背面章节的条记,喜欢的小伙伴「点击左上角」关注我~

正文

1 让自己习惯C++

细节 01:尽量以const,enum,inline 替换 #define

#define 界说的常量有什么不妥?
首先我们要清晰程序的编译紧张的三个阶段:预处理惩罚阶段,编译阶段和链接阶段
#define 是不被视为语言的一部门,它在程序编译阶段中的预处理惩罚阶段的作用,就是做简单的替换。
如下面的 PI 宏界说,在程序编译时,编译器在预处理惩罚阶段时,会先将源码中所有 PI 宏界说替换成 3.14:
  1. 1#define PI 3.14
复制代码
程序编译在预处理惩罚阶段后,才进行真正的编译阶段。在有的编译器,运用了此 PI 常量,如果遇到了编译错误,那么这个错误信息也许会提到 3.14 而不是 PI,这就会让人困惑哪里来的3.14,特别是在项目大的情况下。
解决之道:以 const 界说一个常量替换上述的宏(#define)
作为一个语言变量,下面的 const 界说的常量 Pi 肯定会被编译器看到,出错的时候可以很清晰知道,是这个变量导致的问题:
  1. 1const doule Pi = 3.14;
复制代码
如果是界说常量字符串,则必须要 const 两次,目标是为了防止指针所指内容和指针自身不能被改变:
  1. 1const char* const myName = "小林coding";
复制代码
如果是界说常量 string,则只必要在最前面加一次 const,形式如下:
  1. 1const std::string myName("小林coding");
复制代码
#define 不重视作用域,所以对于 class 的专属常量,应避免使用宏界说。
另有另外一点宏无法涉及的,就是我们无法利用 #define 创建一个 class 专属常量,由于 #define 并不重视作用域。
对于类里要界说专属常量时,我们依然使用 static + const,形式如下:
  1. 1class Student {
  2. 2private:
  3. 3    static const int num = 10;
  4. 4    int scores[num];
  5. 5};
  6. 6
  7. 7const int Student::num; // static 成员变量,必要进行声明
复制代码
如果不想外部获取到 class 专属常量的内存地址,可以使用 enum 的方式界说常量
enum 会帮你约束这个条件,由于取一个 enum 的地址是不合法的,形式如下:
  1. 1class Student {
  2. 2private:
  3. 3    enum { num = 10 };
  4. 4    int scores[num];
  5. 5};
复制代码
#define 实现的函数轻易出错,并且长相丑陋不易阅读。
另外一个常见的 #define 误用情况是以它实现宏函数,它不会招致函数调用带来的开销,但是用 #define 编写宏函数轻易出错,如下用宏界说写的求最大值的函数:
  1. 1#define MAX(a, b) ( { (a) > (b) ? (a) : (b); } ) // 求最大值
复制代码
这般长相的宏有着太的缺点,比如在下面调用例子:
  1. 1int a = 6, b = 5;
  2. 2int max = MAX(a++, b);
  3. 3
  4. 4std::cout  [url=https://mp.weixin.QQ.com/s/Kmk9kDV4vSAQLrD2bs4PKw]泛型编程的第一步,掌握模板的特性![/url]</p>[indent][size=3]细节 01 小结 - 请记住[/size]
  5. [list]
  6. [*]对于单纯常量,最好以 const 对象或 enum 替换 #define;
  7. [*]对于形式函数的宏,最好改用 inline 函数替换 #define。
  8. [/list][/indent][size=4]细节 02:尽可能使用 const[/size]
  9. [indent][color=inherit]const 的一件奥妙的事情是:它允许你告诉编译器和其他程序员[b]某值应该保持稳定[/b]。[/color]
  10. [/indent][color=inherit][b]1.[/b] 面临[i]指针[/i],你可以指定指针自身、指针所指物,或两者都(或都不)是 const:[/color]
  11. [code]1char myName[] = "小林coding";
  12. 2char *p = myName;             // non-const pointer, non-const data
  13. 3const char* p = myName;       // non-const pointer, const data
  14. 4char* const p = myName;       // const pointer, non-const data
  15. 5const char* const p = myName; // const pointer, const data
复制代码

  • 如果关键词const出如今星号(*)边,表示指针所指物是常量(不能改变 *p 的值);
  • 如果关键词const出如今星号(*)边,表示指针自身是常量(不能改变 p 的值);
  • 如果关键词const出如今星号(*)边,表示指针所指物和指针自身都是常量
2. 面临迭代器,你也指定迭代器自身或自迭代器所指物不可被改变:
  1. 1std::vector vec;
  2. 2
  3. 3const std::vector::iterator iter = vec.begin(); // iter 的作用像 T* const
  4. 4*iter = 10; // 没问题,可以改变 iter 所指物   
  5. 5++iter;     // 错误! 由于 iter 是 const     
  6. 6
  7. 7std::vector::const_iterator cIter = vec.begin(); // cIter 的作用像 const T*
  8. 8*cIter = 10; // 错误! 由于 *cIter 是 const           
  9. 9++cIter;     // 没问题,可以改变 cIter                        
复制代码

  • 如果你希望迭代器自身不可被改动,像指针声明为 const 即可(即声明一个 T* const 指针); —— 这个不常用
  • 如果你希望迭代器所指的物不可被改动,你必要的是 const_iterator(即声明一个 const T* 指针)。—— 这个常用
const 最具有威力的用法是面临函数声明时的应用。在一个函数声明式内,const 可以和函数返回值、各参数、成员函数自身产生关联。
1.函数返回一个常量值,每每可以降低因程序员错误而造成的不测。举个例子:
  1. 1class Rational { ... };
  2. 2const Rational operator* (const Rational& lhs, const Rational& rhs);
复制代码
为什么要返回一个 const 对象呢?缘故起因是如果不这样,程序员就能实现这一的暴力行为:
  1. 1Rational a, b, c;
  2. 2if (a * b = c) ... // 做比较时,少了个等号
复制代码
如果 operator* 返回的 const 对象,可以防备这个没意义的赋值动作。
2. 将 const 实行于成员函数的目标,是为了确认该成员函数可作用于 const 对象。来由如下两个:
来由 1 :
它们使得 class 接口比较轻易理解,由于可以得知哪个函数可以改动对象而哪些函数不行,见如下例子:
  1. 1class MyString
  2. 2{
  3. 3public:
  4. 4    const char& operator[](std::size_t position) const // operator[] for const 对象
  5. 5    { return text[position]; }
  6. 6
  7. 7    char& operator[](std::size_t position)  // operator[] for non-const 对象
  8. 8    { return text[position]; }
  9. 9private:
  10. 10    std::string text;
  11. 11};
复制代码
MyString 的 operator[] 可以被这么使用:
[code]1MyString ms("小林coding"); // non-const 对象
2std::cout

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?用户注册

x

相关技术服务需求,请联系管理员和客服QQ:2753533861或QQ:619920289
您需要登录后才可以回帖 登录 | 用户注册

本版积分规则

帖子推荐:
客服咨询

QQ:2753533861

服务时间 9:00-22:00

快速回复 返回顶部 返回列表