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: 与函数相比异常的频率低的多. 个人以为这个假设不一定成立. 写程序的时候不知道边界情况出现的频率.
---持续更新分割线---