effective C++ 读后感(一) 视C++为一个语言联邦

来源:互联网 发布:淘宝网蓝牙耳机 编辑:程序博客网 时间:2024/06/05 08:36

最近在读effective C++, 有些感想。这本书对于熟悉C++语法,并且想用C++进行开发的程序员有很好的指导意义。书中一共提出了改善程序与设计的55个具体做法,每一点都值得细细琢磨推敲。从这之后的几篇博文将针对每一点结合例子谈谈自己的一些想法。欢迎大家指正。


1.视C++为一个语言联邦

我们都知道,C++是C的一个超集,它与C是兼容的,所以它既支持过程形式,也支持面向对象形式。在我们学C++泛型的时候,会觉得泛型确实给C++提供了更强大的功能,但似乎于面向对象又不是那么紧密。学习标准模板库也会有这样的感觉。

事实上, 我们可以把C++看成一个同四种语言组成的联邦:

1.C 这是最原始的。像int, double, char第基本数据类型,还有数组、指针等都属于这一块。C的目标是高效,所以很多时候为了速度而放弃了异常检查(如数组越界)。

2. Object-Oriented C++。包括类、封装、继承、多态等特性,这个大家也比较熟悉,所以在此不再赘述。

3.Template C++。 就是泛型部分。这属于一种新的编程泛型,叫模板元编程。C++的泛型是非常强大的,以后有时间的话我会将其与Java的泛型来进行比较。虽然模板元编程也是使用泛型,但其实模板元编程与泛型编程还是有差别的。模板元编程注重将很多工作从运行阶段移到了编译阶段。大家有兴趣的话可以参看一下http://blog.csdn.net/ugg/article/details/2703326里举的用泛型计算阶乘的例子。

4. STL。 这是一个Template程序库。它将容器、迭代器、算法和函数对象很好地整合起来了,所以也单独列出来。

有了这个概念,我们在考虑一些编程规则时,就应该结合当前所处的“语言”环境还进行选择了。比如说,在C中,传值一般比传引用要高效。因为传值基本上就是复制内存单元,传引用的话类似传了一个指针,获取值的话还需要借助引用去相应地址地查找。而在Object-Oriented C++中就不是这样了,因为对象传值的话会执行相应的构造函数和析构函数,这时传引用就会比传值要高效了。

下面举一个例子来说明在Object-Oriented C++中传引用比传参数要高效:


#include <iostream>using namespace std;class A {public:A() {}A(A &a) {cout << "get in A's copy constructor\n";}~A() {cout << "get in A's distructor\n";}void print() {cout << "this is A\n";}};void test(A a) {a.print();}int main() {A a;test(a);}

在这个例子中,我们定义了一个类A,它有一个print方法。有一个函数test以A为参数,调用其print方法。

其中我们在调用test时传的是值,这时运行结果为:

get in A's copy constructorthis is Aget in A's distructorget in A's distructor

可以发现在传参时,会另外生成一个对象,调用其复制构造函数,函数结束后,又会调用其析构函数。这样显然效率就低了。

如果把test函数改成传引用:

void test(A &a) {a.print();}

则运行结果为:

this is Aget in A's distructor

有些时候,如果程序编写不够细致的话,传值可能会导致程序崩溃。我们看下面的例子:

#include <iostream>#include <cstring>using namespace std;class A {char *r;public:A(char *b) {int n = strlen(b);r = new char[n + 1];memcpy(r, b, sizeof b);}void print() {cout << r << endl;}~A() {delete[] r;}};void test(A a) {a.print();}int main() {char b[] = "abc";A a(b);test(a);return 0;}

看似没什么问题,在类A中只定义了一个构造函数,为r申了一块存储空间,然后在析构函数中将其释放了。但运行之后会发现会出现“double free or corruption”的错误。原来,是我在类A中忽略了复制构造函数。利用默认的复制构造函数传值时,参数对象的r指针与main函数中a的r指针指向的是同一块地址,导致这一块地址被释放了两次(第一次在test函数返回后,第二次出现在main函数完成之后。从而出错。而如果将传给test的参数改为引用的话,就不会出现这种错误。当然,还是得承认造成这种错误主要还是没有重写复制构造函数(事实上如果没有重载“=”运算,也有可以出现这种错误)。但我们不得不承认,传引用会更安全。

0 0