Effective C++读书笔记

看书《Effective C++》Scott Meyers,看到哪里有趣就写到哪里(一)

导读部分

  1. 构造函数声明为explicit,可以阻止它们被用来执行隐式类型转换,但它们仍然可以被用来执行显示转换。
class C
{
public:
	explicit C(int x);
}

对这个关键字更详细的解释点击这里,这个博主写的非常好,我也是看了才理解了。书中说:

被声明为explicit的构造函数通常比其他非explicit的更受欢迎,因为他们禁止编译器执行非预期(往往也不被期望的)类型转换,除非有一个好理由允许构造函数进行隐式转换,否则我会把它声明为explicit,鼓励你遵循。

  1. copy 构造函数和 copy assignment 运算符
    copy构造函数(以同类型对象初始化自我对象),copy assignment操作符(从另一同类型的对象中拷贝其值到自我对象)
Class Widget{
public:
	Widget(); //默认构造函数
	Widget(const Widget& rhs); //copy构造函数
	Widget& operator=(const Widget& rhs); //copy assignment 操作符
	...
}
Widget w1; // 调用默认构造函数
Widget w2(w1); // 调用copy构造函数
w2 = w1 //调用copy assignment 操作符
Widget w3 = w2; //调用copy构造函数

Widget w3 = w2;这一个比较有迷惑性,“=”不仅可以调用copy赋值,也可以调用copy构造,如果一个新对象被定义则一定是调用构造函数的,正如这里的w3,如果没有新对象被定义,就是操作符被调用了。copy构造函数是一个很重要的构造函数,因为它定义了一个对象如何以值传递!!!之后再聊这个。

第一章:让自己习惯C++
1. 尽量以 const,enum,inline 替换 #define
原因:例如 #define ASP 1.653在编译器开始处理源码的时候ASP就被预处理器拿走了,所以ASP有可能没进入记号表(Symbol table)中,当你运用此常量发生编译错误时,这个错误信息可能提到1.653,而提不到ASP,如果这代码还不是你写的,你还得去找这个1.653岂不挺崩溃的。
解决:const double ASP = 1.653,当我们以常量代替#define时有两个注意事项:1)定义常量指针:由于常量的定义通常在头文件中(以便被不同的源码含入)因此有必要将指针声明为const。2)注意class专属常量,为了将常量的作用域限制于class内,必须让他成为class的一员,为确保此常量至多仅有一份实体,必须让他成为一个static成员。
另一个常见的#define误用情况是用它实现宏,
例如:#define CALL_WITH_MAX(a,b) f((a) > (b) ? (a) : (b))
第一个问题是不论何时使用这种宏都必须为所有实参加上小括号,否则可能遇到麻烦。
再个问题:如下代码,调用f之前,a的递增次数居然取决于他被拿来和谁比较。

int a = 5,b = 0;
CALL_WITH_MAX(++a,b);  // a被累加2次
CALL_WITH_MAX(++a,b+10); // a被累加1次
/*不知道为什么累加次数不同的朋友评论@我,告诉你,
这个问题明白的自然就知道#define函数弊端在哪里了*/

解决:inline写一个模板函数比啥都好使

template<typename T>
inline void callwithmax(const T& a,const T& b)
{
	f(a > b ? a : b);
}

2. 尽可能地使用const
1)多才多艺的const

char greeting[] = "Hello";
char* p = greeting;              //non-const pointer ,non-const data
const char* p = greeting;		 //non-const pointer ,const data
char* const p = greeting;		 //const pointer ,non-const data
const char* const p = greeting;  //const pointer, const data
/*总之呢,const出现在*左边表示被指物是常量;如果出现在*右边表示指针自身是常量
两边都有,那就都是常量*/
那你猜,const char* p 和 char const *p 有什么关系呢??不会真有人去评论去问吧。

2)STL迭代器和指针
迭代器的作用像是一个T指针,声明一个T const指针,表示这个迭代器不得指向不同的东西,但他所指的东西的值是可以改动的,如果你希望迭代器所指的东西不能被改动那就是const T*,(const_iterator)
Effective C++读书笔记_第1张图片

3. 确定对象在使用前已被初始化
1)读未初始化的值会产生不明确的行为,不要混淆了赋值和初始化,C++规定,对象的成员变量的初始化动作发生在进入构造函数本体之前。赋值操作是在两个已经存在的对象间进行的,而初始化是要创建一个新的对象,并且其初值来源于另一个已存在的对象。编译器会区别这两种情况,赋值的时候调用重载的赋值运算符,初始化的时候调用拷贝构造函数。如果类中没有拷贝构造函数,则编译器会提供一个默认的。这个默认的拷贝构造函数只是简单地复制类中的每个成员。
这里有个例子,这个博主写的例子就很好。
2)C++有着固定的“成员初始化次序”,基类更早于派生类被初始化,类成员总是以其声明次序而被初始化。这个知识点也蛮重要的,
有个不错的的例子在这里,这篇博客的分享也很好理解。

这本书学习还是很重要的,值得多来几次,第一章遗漏的东西还有一些,等我理解透了再写,这本书真是值得多看几次。

你可能感兴趣的:(Effective,C++,c++,编程语言)