more effective c++ 第一章读书笔记: 指针,引用,c++类型转换,多态数组,默认构造函数

本文探讨了C++编程中的几个关键概念,包括指针与引用的区别、C++风格的类型转换、多态在数组中的应用及默认构造函数的重要性。通过具体示例,帮助读者深入理解这些概念。

这是一本很不错的书,推荐大家去看。当然书中说的不一定完全对,读者需要自己去思考和理解。

 

本文记录的是我自己的一些看法。

 

条款一: 区分指针和引用。

 

当然,这是个老生常谈的话题。作者从语义上讨论了两者的适用情况。引用由于声明的时候必须初始化,而且初始化之后,再也不能引用别的对象,而指针声明的时候不需要初始化,初始化后指针还是可以指向别的对象。

而且书中有这样一个例子:

char* pc = 0;

char& rc = *pc;

我个人觉得这不是一个很好的例子。因为这明摆了就是对一个空指针的解引用.而且这个例子并不能说明什么问题。在最新的VS2010里,编译器会给出一个警告。(VS的低一点的版本没有)

一个更好的例子是

char* p = NULL;

char*& rc = p;

这里声明的rc引用的是p。这里rc引用的是一个NULL指针。此时编译器没有任何警告。当然,这是一个很诡异的例子,c++中如此诡异的东西并不少。这是需要大家非常小心的。指针的引用其实没什么作用。记得我毕业找工作时,面试群硕的时候,面试官给了我两个引用声明:

char*& c和char&* c,问哪一个是正确的。很遗憾我那时分不清楚,于是我毫无疑问的被鄙视了。不过庆幸的是我没去,隔壁班去群硕的同学在里面被剥削的不行,不到两年纷纷跳槽。群硕不是一个好的公司。希望有能力的朋友去之前三思。

 

条款二 : 优先考虑c++风格的类型转换。

 

c++的类型转换的目的是为了改良c语言的类型转换。于是c++创造了四个类型转换关键字: static_cast, const_cast, dynamic_cast,reinterpret_cast.通常他们的语法是static_cast<type>(expresison).

static_cast和c的转换基本有想同的语义。一般用来做静态转换。

const_cast用来去除一个常量的常量属性。实际上比较微妙的是这一般用来在传递参数时,进行类型转换,临时去除常量属性。实际上const_cast并不能最终改变原来对象的const属性。比如说对于一下代码:

 

const int a = 20;

int& j = const_cast<int&>(a);

j = 30;

cout << a << endl;

cout << j << endl;

编译器的输出是20,30.

而且,如果你不用const_cast,简单的一个c类型转换也同样可以达到同样的效果。不信你可以试试。

所以我认为对已static_cast和const_cast,说白了就是对c风格转换的名字包装而已,实际上并没有变什么。reinterpret_cast同样也是如此。

给一个书中的宏定义:

#define static_cast((type), (expression))  ((type))((expression))

#define const_cast((type), (expression))  ((type))((expression))

#define reinterpret_cast((type), (expression))  ((type))((expression))

功能是差不多的。对于某些书中说,c++程序员不需要宏定义,个人觉得这也是很无聊的。宏定义是每个c/c++程序员必须掌握的技能之一啊!!

 

唯一的例外是dynamic_cast,宏定义无法判断失败,但是dynamic_cast可以。转换失败的时候,dynamic_cast会返回NULL。如果你希望返回的不是null,而是抛出一个异常,你可以这样封装:

template<class Target, class Source>

inline Target* my_cast(Source* s)

{

   Target* temp = dynamic_cast<Target*>(s);

   if (temp == NULL)

      throw std::bad_cast();

    return temp;

}

这正是boost::polymorphic_cast的实现。

同样,你也可以这样实现static_cast:

template<class Target, class Source>

inline Target my_static_cast(Source s)

{

    return (Target)Source;

)

 

关于c++的类型转换我就只想这么多了。如果你有更好的建议,你可以联系我。或者发表评论。

 

条款三: 不要把多态应用于数组。

个人觉得这个条款属于设计上的问题。读者可以跳过。

 

条款四: 避免不必要的默认构造函数。

 

对于c++的默认构造函数,在inside c++ object model这本书讲的很清楚。当你不声明任何构造函数时,编译器会帮你隐式的声明一个默认构造函数。需要指出的是,默认构造函数通常指的是没有参数的构造函数。在某些情况下,编译器会帮你生成一个non-trivial的构造函数,比如说你的类里面有一个其他复杂类型,或者在继承体系里,声明了虚函数的情况下,此时编译器帮你生成的non-trivial的构造函数里会调用这些类型的默认构造函数,基类的默认构造函数,初始化虚函数表等等。在其他情况下,编译器会认为此时的默认构造函数是trivial的,此时编译器不会为你生成默认构造函数。

 

我人为这一章的内容还是有点意思的。从设计和语言特性上来说,某些时候默认构造函数是必须的,而有时候默认构造函数却不是必须的。因此这需要你来权衡。不过我个人觉得提供默认的构造函数,并在默认构造函数里初始化类的资源和变量是一个很好的习惯。当然了,这只是我的个人看法。

 

此外,书中有一个例子很有意思,如何用友参数的构造函数来初始化一个对象数组:

class A

{

    int i;

public:

    A(int i_):i(i_) {}

};

 

void * rawmemory = operator new[](10*sizeof(A));

A* array_of_A = (A*)(rawmemory)'

for(int i = 0; i < 10; i++)

  new (array_of_A+i)A(i);

 

使用完删除:

 

for(int i = 0; i < 10; i++)

    array_of_A[i]->~A();

operator delete[] rawmemory;
STL的allocator的实现也用了以上类似的做法。关于c++的operator new,operator delete,placement new, placement delete,这实在不是适合新手看的。it is so tough. anyway, it  is a not book for beginners.
好了,先写到这吧,接下来会有关于第二章的读书笔记。希望自己能够勤快点,快点把这本书看完。

 

 

 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值