c++设计和演化 笔记

来源:互联网 发布:人工智能对话app 编辑:程序博客网 时间:2024/05/29 16:55

P60: cpp的语法,太复杂了,不止cpp. 很多语言也是这样甚至更甚(对比是lisp-1).

 

P76: const 的设计引发的问题不少(比如在模板 的时候 const会让代码指数级膨胀(虽然remove_refance能修补一些)). 如果在const引入之前引入了多重继承的话 也许有更好的解决方法.

 

P83: 构造/析构 函数的命名. 用类型名做构造函数名字, 在某些(比如模板)生成代码的时候 会产生一些困惑 (pf= T::T /* ::后面应该是symbol但是是type*/) .

 

P88: 每个语句都产生一个值是好想法, 但是 if(Tok* ct= gettok()){...} 还是有些奇怪.这个和P60也有关系.

 

P95: 关于静态类型"...通过静态类型...更可能是重视地表达了一种深思熟虑 的设计".  但是问题是很多设计太大了 以至于深思熟虑是技术上不可能的.  (他自己也在P92说了"一个 好语言不是设计出来的,而是成长起来的.").  所以说这样的静态类型(或者说语法上避免动态类型)是否是最佳方案还是存疑的.

 

P130: 语言的扩充 cpp作者和委员会在扩充上遇到了一些问题 以至于采取了很保守的策略, 这也导致了cpp的进化速度太慢. 现阶段我认为还是过于保守了,如果鼓励方言(抽取共同的部分作为标准)的话应该会好一些.

 

P252: 关于构造函数和虚函数.

class box: public shape{ point lt,rb;public: point get_center(){ return (lt+rb)/2; } //...};
class shape{public: point center; shape(){  f(); //OK  center= get_center(); //ERROR 使用了没有初始化的虚函数 } int f(){...} virtual point get_center()=0;};

这样的代码是不行的, 因为box依赖于基类shape. 而shape的构造函数又依赖于子类box. 形成一个环.

c++的解决方法是在构造函数不可以调用虚函数.

但是 确实有需求怎么办,比如我就想在shape中 提供center.

只能把center从对象变成接口,然后把具体对象放在子类中:
class shape{public: //... virtual void set_center(point)=0; virtual point get_center()=0;};

这就引发了一个新问题. 在定义class的时候必须事先知道这个class是基类还是子类以决定放置对象还是接口.

这就变相的让一个子类失去了成为别人基类的能力,也就是影响了正交性.

比如,你需要给一个基本完善的对象做细微调整的时候,你想重载一个函数,但是这个函数被用在了基类的构造函数里,你就不能重载它,因为这个函数不可能被声明为virtual.

 

这时候只能用一些不怎么漂亮的办法:

class point{ vector<float> data;public: point(){} void init(){  data.resize(get_D()); } float operator[](size_type); virtual size_type get_D()=0;};
class point3D: public point{public:virtual size_type get_D(){return 3;}};
void g(point*);void f(){ point3D p(); p.init(); g(&p); //...}

使用这个办法需要两个东西支持:

第一是调用的时候必须手动调用init(), 附加的,在使用别的函数的时候可能也需要检测是否init()过的成本.

第二是被初始化的东西(此例是vector<float>)必须有无参数的构造函数(或者类似的东西).否则异常退出的时候不能保证安全性.

 

二没办法解决, 一的解决可以是这样:

class point3D_warp{ point3D data;public: point3D_warp(){data.init();} float operator[](size_type i){ return data[i]; } //...};

 

 

P254: const

const函数访问非const成员

#include<iostream>using namespace std;class dc{public: int n; int& deconst_n; dc():n(0),deconst_n(n){} int const_f()const{  return ++deconst_n; }};int main(int argc, char** argv){ dc odc; const dc& co=odc; int n=10; cout<<co.const_f()<<endl; return n;}


P255: mutable最初的名字是 ~const  哈哈哈, 不过我觉得还是~const比较好. 

 

P294: RTTI

class a{int i;};class b{public: int i;};class d: public a, public b{public: int i;};int main(int argc, char** argv){ d* pdo= new d(); pdo->i=42; b* pb= pdo; d* pd1= reinterpret_cast<d*>(pb); d* pd2= static_cast<d*>(pb); cout<<typeid(b).name()<<endl; cout<<typeid(*pd1).name()<<"   "<<pd1->i<<endl; cout<<typeid(*pd2).name()<<"   "<<pd2->i<<endl; return 0;}


 P338: 与函数相比异常的频率低的多. 个人以为这个假设不一定成立. 写程序的时候不知道边界情况出现的频率.

 

 

---持续更新分割线---