锁定老帖子 主题:朴实的C++设计
该帖已经被评为精华帖
|
|
---|---|
作者 | 正文 |
发表时间:2010-08-18
我猜Solstice是明白我想说什么的。
一方面说设计模式都在摆谱,一方面为了实现一个so easy的需求不得不然,嘿嘿... |
|
返回顶楼 | |
发表时间:2010-08-18
从实现细节和某些设计角度考虑,PImpl和delegate并无不同。不能一个你生的孩子,大牛过来摸一下顶,说句:“这孩子不错...”。完了孩子就跟人家姓了,是吧。其实这也不是最重要的,不管跟谁姓,它也是OO,也是设计模式。所以还是我赢了。
|
|
返回顶楼 | |
发表时间:2010-08-19
用C的方式写c++,为什么不直接用c呢,就是为了用析构?
|
|
返回顶楼 | |
发表时间:2010-08-30
面向对象讲的是组合,面向过程讲究的是独立。
独立显然比组合更灵活,但是如果你的需求本来就是大量的组合的话,面向对象的优势就体现出来了。 比如file1.open, file1.read, file1.close这种模式化的操作,还是比handle1=fopen(), fread(handle1), fclose(handle1),handle1=0这种形式更容易避免出错的。再比如try catch和hResult两种错误处理方式,显然后者需要更多的用到if判断来销毁残余的资源,当然出错的可能性更大。 就编程的本质而言,最终肯定是汇编成顺序执行的东西,所以面向过程是主体,决定了系统能不能提供你需要的东西。而面向对象则是对一些可以提供便利的地方加以改进,让你更快更安全的解决问题。 |
|
返回顶楼 | |
发表时间:2010-08-30
hatedance 写道 1 OO的性能肯定比PO低。因为OO的机制比较复杂。比如继承和多态,导致随便调用一个函数都有可能要找遍所有的父类有没有对应的函数。所以说像linux或者网络服务器这种讲究性能的程序,用c肯定是没错的。
2 OO首先是一种设计思想,然后才有OO编程语言。OO语言是一种工具让我们方便的用它来写出我们的OO设计。所以,用OO思想设计的系统就应该用OO语言来写代码,用PO设计的系统就最好用PO语言来写。 所以,像LZ这样的情况,是属于用PO思想设计的系统,最后用错了语言,选用了CPP这样一种支持OO编程的语言。但是仍然不要紧,因为CPP和java以及其他大多数支持OO编程的语言,都是同时支持OO和PO编程的。 关于语言和范式的知识,可参考http://en.wikipedia.org/wiki/Programming_paradigm 这话我可不敢苟同。网络服务器采用oo语言而一样取得高效率的例子太多了。继承和多态并没有占用太多的开销,把性能低下归结为几条汇编指令,实在有些荒谬。 OO是什么思想,它到底是不是有用,这个问题没必要讨论。因为对OO根本就没有明确的定义。什么样的东西叫OO?怎样就不OO了?用了一次继承,其它都没用,是不是就OO了? 在c语言的编程中,经常也会用到类似封装和多态的处理方法,是不是就一定不算OO了? 是否OO无关紧要,关键是OO所带来的那些好处是否真的被程序员了解了。 OO的好处,不在于效率,它的弱点也不在于效率。OO的好处是它可以降低软件的开发成本。它真正的优势,是有效的管理,易于理解的表达方式,以及易于扩展的框架。 不管OO不OO,能写得又快又稳定,扩展性还好,就是王道。 最后说句让你们会丢我砖头的话,其实c#最高效实用(做app)。虽然我用任何一种主流编程语言都会比90%的程序员开发速度快,但我还是觉得c#最简洁。 |
|
返回顶楼 | |
发表时间:2010-08-30
jimmy_c 写道 我的感觉,所有对于OO的批判,对于继承和多态的批判,去追寻炮轰者理论的根源,其实都在于template模式。
原因很简单,只要你遵循C++的语法,大概知道了多态的概念,想着要把这一伟大理论应用于自己的代码,写上个最简单的一个基类,两三个派生类的简单类结构,就自然而然地形成了template模式。 在这里多一句嘴,此template非彼template,是设计模式的概念,而非C++语法中的那个更伟大的关键词。诸位习惯于搞不清虚函数概念,把C++和script混为一谈,搞不清Functional Programming和Procedure Programming概念区别的同学们就不要发表高论了。 不过template模式其实更应该被称作是“template反模式”。因为它的bad smell不是一般地大。所有派生类依赖于基类,它们能够自主的不过是一些可怜的虚函数重载。基类的内部实现逻辑无条件地扩散和统治了所有的派生类。同时由于基类头文件必包含于派生类头文件中,所以所有引用派生类的代码和相关逻辑无一例外会被基类“污染”。基类内部实现的任意一点疑问和错误,对于运行环境的考量,异常处理,等等所有你能想到的问题都会被无限的放大。 而template模式本身对于这些问题的解决大约只有将基类写得尽善尽美,包罗万象。由此产生了一个又臭又长的代码文件。很多的C++类库中都会有这样让人不知所云的文件。 而正确的方法,应该是非常谨慎地限制使用这种模式,非常局部地使用它。 由对template模式的批判,而上升到对继承/多态的批判,甚至对于所有设计模式的批判,我觉得是非常幼稚的。对于“继承树”的建模形式的批判,本身是没有错的。但我想这应该不是我们使用OO的全部。我们不能把孩子和脏水一起倒出去。 我想至少有以下一些理由值得我们使用OO和设计模式,详细的讨论涉及太多细节和代码,所以只写我的论点,没有论述: 1. 依赖倒置原则。代码不应该依赖于具体的实现,而应该依赖于抽象。 典型的是Java的interface的编程风格。 2. Open-Close原则。 3. 没有上帝原则。我们不能把设计人员当成上帝,他们不能预知未来,所以设计变更是必然的;我们不能要求programmer是上帝,他们不会知晓所有技术和所有代码细节,所以请让他们专注于实现自己的问题;我们不能允许代码模块是上帝,它们绝不能全知全能,应该只包含最少的外部引用,并尽量少地引入逻辑依赖; 4. 最少修改原则。代码需要修改的时候,应该做尽量少的修改,并且修改的地方应该和修改原因明显相关; 5. 不装蛋原则。内涵简单的东西,用简单的形式表示出来,让人一目了然。更多的时候,写的代码让别人看得懂才是最难的。 软件帖的难度在于,对于一个问题的描述,最好使用代码。然而太多时候短代码是很难描述工程中的实际问题的。只好举一个最简单的我称为污染性的问题,说明继承的作用: class A { public: void func(); private: T1 myFunc(T2 myParam); private: T3 _myVariable; }; 这里就有了一个问题,T1/T2/T3是内部实现细节,我并不想把它们引出到外部模块中去。但是C++的语法导致所有引用类A的代码必然知晓T1/T2/T3。 于是我们的代码成为了上帝。我们创造了上帝。不过这种感觉一点儿也不好。 我的解决方法如下: class A { public: virtual void func() = 0; }; class AImplement : public A { public: virtual void func(); private: T1 myFunc(T2 myParam); private: T3 _myVariable; }; 然后可以通过一个Factory或者是Singleton,或是其它创建型模式,可以创建A对象。具体选择依需求而定。比如最简单的函数: A* Instance() { return new AImplement(); } 这样外部可以选择只引用A,而不需要引用其内部细节和让人讨厌的内部逻辑。 当然还有另一种方法,比如说把成员函数T1 myFunc(T2)变成一个真正的函数T1 myFunc(A* pThis, T2)不也可以至少去掉讨厌的类型T1, T2么? 然而绝大多数时候由于myFunc内部引用了成员变量_myVariable,导致这样是不可行的。否则我们就要同时把_myVariable变为public才可以。 template模式其实没啥好批判的。它一般都是用于代码实现,而不是用于接口设计。属于战术武器。非得把战术武器用于战略性的决战,那是指挥者本身的问题。 啥模式不模式的,讨论起来实在绕口。代码写多了,自然就会了。 |
|
返回顶楼 | |
发表时间:2010-09-07
(这篇文章写于 2007 年底 ) (这篇文章写于 2007 年底 ) (这篇文章写于 2007 年底 ) (这篇文章写于 2007 年底 ) (这篇文章写于 2007 年底 ) (这篇文章写于 2007 年底 ) (这篇文章写于 2007 年底 ) (这篇文章写于 2007 年底 ) (这篇文章写于 2007 年底 ) (这篇文章写于 2007 年底 ) (这篇文章写于 2007 年底 ) (这篇文章写于 2007 年底 ) (这篇文章写于 2007 年底 ) (这篇文章写于 2007 年底 ) (这篇文章写于 2007 年底 ) (这篇文章写于 2007 年底 ) (这篇文章写于 2007 年底 ) (这篇文章写于 2007 年底 ) (这篇文章写于 2007 年底 ) (这篇文章写于 2007 年底 ) (这篇文章写于 2007 年底 ) (这篇文章写于 2007 年底 ) (这篇文章写于 2007 年底 ) (这篇文章写于 2007 年底 ) (这篇文章写于 2007 年底 ) (这篇文章写于 2007 年底 ) (这篇文章写于 2007 年底 ) (这篇文章写于 2007 年底 ) (这篇文章写于 2007 年底 ) (这篇文章写于 2007 年底 ) (这篇文章写于 2007 年底 ) (这篇文章写于 2007 年底 ) (这篇文章写于 2007 年底 ) (这篇文章写于 2007 年底 ) (这篇文章写于 2007 年底 ) (这篇文章写于 2007 年底 ) (这篇文章写于 2007 年底 ) (这篇文章写于 2007 年底 ) (这篇文章写于 2007 年底 ) (这篇文章写于 2007 年底 ) (这篇文章写于 2007 年底 ) (这篇文章写于 2007 年底 ) (这篇文章写于 2007 年底 ) (这篇文章写于 2007 年底 ) (这篇文章写于 2007 年底 ) (这篇文章写于 2007 年底 ) (这篇文章写于 2007 年底 ) (这篇文章写于 2007 年底 ) (这篇文章写于 2007 年底 ) (这篇文章写于 2007 年底 ) (这篇文章写于 2007 年底 ) (这篇文章写于 2007 年底 ) (这篇文章写于 2007 年底 ) (这篇文章写于 2007 年底 ) (这篇文章写于 2007 年底 ) (这篇文章写于 2007 年底 ) (这篇文章写于 2007 年底 ) (这篇文章写于 2007 年底 ) (这篇文章写于 2007 年底 ) (这篇文章写于 2007 年底 ) (这篇文章写于 2007 年底 ) (这篇文章写于 2007 年底 ) (这篇文章写于 2007 年底 ) (这篇文章写于 2007 年底 ) (这篇文章写于 2007 年底 ) (这篇文章写于 2007 年底 )
|
|
返回顶楼 | |
发表时间:2010-09-18
实用的就是最好的~
|
|
返回顶楼 | |
发表时间:2010-11-03
wandou 写道 jimmy_c 写道 我的感觉,所有对于OO的批判,对于继承和多态的批判,去追寻炮轰者理论的根源,其实都在于template模式。
原因很简单,只要你遵循C++的语法,大概知道了多态的概念,想着要把这一伟大理论应用于自己的代码,写上个最简单的一个基类,两三个派生类的简单类结构,就自然而然地形成了template模式。 在这里多一句嘴,此template非彼template,是设计模式的概念,而非C++语法中的那个更伟大的关键词。诸位习惯于搞不清虚函数概念,把C++和script混为一谈,搞不清Functional Programming和Procedure Programming概念区别的同学们就不要发表高论了。 不过template模式其实更应该被称作是“template反模式”。因为它的bad smell不是一般地大。所有派生类依赖于基类,它们能够自主的不过是一些可怜的虚函数重载。基类的内部实现逻辑无条件地扩散和统治了所有的派生类。同时由于基类头文件必包含于派生类头文件中,所以所有引用派生类的代码和相关逻辑无一例外会被基类“污染”。基类内部实现的任意一点疑问和错误,对于运行环境的考量,异常处理,等等所有你能想到的问题都会被无限的放大。 而template模式本身对于这些问题的解决大约只有将基类写得尽善尽美,包罗万象。由此产生了一个又臭又长的代码文件。很多的C++类库中都会有这样让人不知所云的文件。 而正确的方法,应该是非常谨慎地限制使用这种模式,非常局部地使用它。 由对template模式的批判,而上升到对继承/多态的批判,甚至对于所有设计模式的批判,我觉得是非常幼稚的。对于“继承树”的建模形式的批判,本身是没有错的。但我想这应该不是我们使用OO的全部。我们不能把孩子和脏水一起倒出去。 我想至少有以下一些理由值得我们使用OO和设计模式,详细的讨论涉及太多细节和代码,所以只写我的论点,没有论述: 1. 依赖倒置原则。代码不应该依赖于具体的实现,而应该依赖于抽象。 典型的是Java的interface的编程风格。 2. Open-Close原则。 3. 没有上帝原则。我们不能把设计人员当成上帝,他们不能预知未来,所以设计变更是必然的;我们不能要求programmer是上帝,他们不会知晓所有技术和所有代码细节,所以请让他们专注于实现自己的问题;我们不能允许代码模块是上帝,它们绝不能全知全能,应该只包含最少的外部引用,并尽量少地引入逻辑依赖; 4. 最少修改原则。代码需要修改的时候,应该做尽量少的修改,并且修改的地方应该和修改原因明显相关; 5. 不装蛋原则。内涵简单的东西,用简单的形式表示出来,让人一目了然。更多的时候,写的代码让别人看得懂才是最难的。 软件帖的难度在于,对于一个问题的描述,最好使用代码。然而太多时候短代码是很难描述工程中的实际问题的。只好举一个最简单的我称为污染性的问题,说明继承的作用: class A { public: void func(); private: T1 myFunc(T2 myParam); private: T3 _myVariable; }; 这里就有了一个问题,T1/T2/T3是内部实现细节,我并不想把它们引出到外部模块中去。但是C++的语法导致所有引用类A的代码必然知晓T1/T2/T3。 于是我们的代码成为了上帝。我们创造了上帝。不过这种感觉一点儿也不好。 我的解决方法如下: class A { public: virtual void func() = 0; }; class AImplement : public A { public: virtual void func(); private: T1 myFunc(T2 myParam); private: T3 _myVariable; }; 然后可以通过一个Factory或者是Singleton,或是其它创建型模式,可以创建A对象。具体选择依需求而定。比如最简单的函数: A* Instance() { return new AImplement(); } 这样外部可以选择只引用A,而不需要引用其内部细节和让人讨厌的内部逻辑。 当然还有另一种方法,比如说把成员函数T1 myFunc(T2)变成一个真正的函数T1 myFunc(A* pThis, T2)不也可以至少去掉讨厌的类型T1, T2么? 然而绝大多数时候由于myFunc内部引用了成员变量_myVariable,导致这样是不可行的。否则我们就要同时把_myVariable变为public才可以。 template模式其实没啥好批判的。它一般都是用于代码实现,而不是用于接口设计。属于战术武器。非得把战术武器用于战略性的决战,那是指挥者本身的问题。 啥模式不模式的,讨论起来实在绕口。代码写多了,自然就会了。 template 现在有向functional programming化的倾向。。。 template + operator overload,c++可以玩出巨多花样。。估计这是有些人不爽的原因... |
|
返回顶楼 | |
发表时间:2010-11-04
最后修改:2010-11-08
jimmy_c 写道 好了。这个例子的讨论到此为止。
还是那个“不装蛋原则”。C++的模板技术,从实践上来说还是很失败的。推出十几年,除了STL和经常用于补裤裆的boost,未见什么GP技术设计的经典之作。我想在这方面想继续尝试的新朋友们可以止步了。至于什么“改变C++设计风格”的炎炎之言,还是少说为好吧! 我推测模板技术应该有很多经典之作,看书中也说STL只是模板技术的一盘小菜了。我只用过BGL库,CGAL中和BGL的结合层,如果没有模板,是搞不定的。 PS: BGL和CGAL是几何算法库。BGL可对任何类型,任何精度要求,任何坐标系的自定义类型无缝结合,非常酷。 http://geometrylibrary.geodan.nl/index.html 问一下,GP技术是啥意思? |
|
返回顶楼 | |