Thinking in C++ (1-11) 小结

小结

这一章为您带来对于面向对象编程以及C++概括的讨论,其中包括:为什么说OOP是全新的,尤其是C++OOP方法论的概念,以及当你期望迁移到OOPC++时所需要了解的事情。

OOPC++并是对每个人都适合的。估算出你的需求并且决定C++是否是解决这些需求的最佳工具,这显得十分重要,否则你将得不到C++带来的好处,也许使用其它的编程系统(包括当前你正在使用的)你可能会做得更好。 如果你清楚这一点,你就可以针对已经预测好的未来更加专心的钻研专门的语言知识,如果你觉得C++无法让你无拘无束的大展拳脚,那么你就应该为自己考虑找一个替代品[1]。即使你最终选择了C++作为你的编程语言,至少你了解了都有哪些可选择的语言,同时也会对于你为什么选择这条路有一个更清醒的认识。

我们都很清楚过程语言是什么样的:我们所做的主要就是数据定义和函数调用。为了弄清一个过程语言程序的含义,你需要观察函数调用的情况,并且要清楚一些底层概念。这就是为什么我们在编写过程语言程序时需要一个中间代表,由于过程语言更多的是面向计算机而不是面向你所解决的问题,这些程序往往不容易理解。

由于C++C语言中添加了许多新的概念,你自然会联想到,C++程序中的main( )函数是否与等价的C语言程序有很大的差别呢。这里你会得到一个惊喜:一个优秀的C++程序比等价的C程序要简单得多,并且更加易于理解。你所看到的是代表问题空间中的概念的对象的定义(而不是代表计算机),以及为了表示问题空间中的行为,而对这些对象发送的消息。面向对象编程令人爱不释手的原因之一就是,如果掌握了好的设计编程习惯,那么你的代码便更加易于理解。同样,由于现有的类库可以帮助你解决很多问题,代码也会变得更加精炼。



[1] 我向大家特别推荐Java(http://java.sun.com) Python(http://www.Python.org)

 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
一、下载须知: .................本书无目录 .................本书经过内容识别处理,所以好处就是书上的案例源码可以直接粘贴复制到编辑器中,当然有个别括号什么的可能需要自己纠正一下。 ................本书高清 ...............本书是和代码结合在一起讲解的,其中也讲到了运行时类的识别等等。 二、截取部分章节 《第18章:运行时类型识别》 RTTI的两种使用方法 使用RT T I有两种不同的方法。第一种就像s i z e o f ( ),因为它看上就像一个函数。但实际上它是 由编译器实现的。t y p e i d ( )带有一个参数,它可以是一个对象引用或指针,返回全局t y p e i n f o类的 常量对象的一个引用。可以用运算符“= =”和“!=”来互相比较这些对象。也可以用n a m e ( )来 获得类型的名称。注意,如果给t y p e i d ( )传递一个s h a p e *型参数,它会认为类型为s h a p e *,所以如 果想知道一个指针所指对象的精确类型,我们必须逆向引用这个指针。比如,s是个s h a p e * , cout << typeid(*s).name()<<endl; 将显示出s所指向的对象类型。 也可以用b e f o r e ( t y p e i n f o & )查询一个t y p e i n f o对象是否在另一个t y p e i n f o对象的前面(以定 义实现的排列顺序),它将返回t r u e或f a l s e。如果写: if(typeid(me).before(typeid(you))) //... 那么表示我们正在查询m e在排列顺序中是否在y o u之前。 RT T I的第二个用法叫“安全类型向下映射”。之所以用“向下映射”这个词也是由于类继 承的排列顺序。如果映射一个c i r c l e *到s h a p e *叫向上映射的话,那么将一个s h a p e *映射成一个 c i r c l e *就叫向下映射了。当然一个c i r c l e *也是一个s h a p e *,编译器允许任意的向上映射,但一 个s h a p e *不一定就是c i r c l e *,所以编译器在没有明确的类型映射时并不允许我们完成一个向下 映射任务。当然可以用原有的C风格的类型映射或C + +的静态映射(s t a t i c c a s t ,将在本章末介绍) 来强制执行,这等于在说:“我希望它实际上是一个c i r c l e *,而且我打算要求它是。”由于并没 有明确地知道它实际上是c i r c l e,因此这样做是很危险的。在开发商制定的RT T I中一般的方法 是:创建一个函数来试着将s h a p e *指派为一个c i r c l e * (在本例中),检查执行过程中的数据类型。 如果这个函数返回一个地址,则成功;如果返回n u l l,说明我们并没有一个c i r c l e *对象。 C + +的RT T I的“安全类型向下映射”就是按照这种“试探映射”函数的格式,但它(非常 合理地)用模板语法来产生这个特殊的动态映射函数( d y n a m i c c a s t),所以本例变成: 动态映射的模板参数是我们想要该函数创建的数据类型,也就是这个函数的返回值。函数 参数是我们试图映射的源数据类型。 通常只要对一种类型作这种工作(比如将三角型变成紫色),但如果想算出各种s h a p e的数 目,可以用面下例子的框架: 当然这是人为的—我们可能已经在各个类型中放了一个静态数据成员并在构造函数中对 第18章运行时类型识别383 下载 shape* sp = new circle; circle* cp = dynamic_cast<circle*>(sp); if(cp) cou七<< "cas 七successful"; circle* cp = dynamic_cas区circle*>(sh); square* sp = dynamic_cast<square*>(sh); triangle* 七p = dynamic_cast<triangle*>(sh); 它自增。如果可以控制类的源代码并可以修改它,当然可以这样做。下面这个例子用来计算 s h a p e的个数,它用了静态数据成员和动态映射两种方法: 384 C + +编程思想 下载 //: RTSHAPES.CPP -- Counting shapes #include <iostream.h> #include< 七ime.h> #include <typeinfo.h> #include"·.\14\tstash.h" class shape { protected: S 七atic in七coun店 public: shape() { count++; vir七ual -shape() = O { count--; } vir七ual void draw () const = O; static in七quan七让y() { return count; }; in七shape : : count = O; class rectangle : public shape void operator=(rectangle&); // Disallow protected: static int count; public: rectangle() { count++; rectangle(const rectangle&) { count++;} -rectangle() { count--; } void draw () cons 七{ cout << "rec 七angle: : draw ()" << endl; S 七atic int quantity() { return count; } ... ' int rectangle: : count = 0; class ellipse : public shape void operator=(ellipse&}; // Disallow protected: static int count; public: ellipse () { count++; } ellipse (const ellipse&) { count++; } ~ellipse() { count 一;} void draw() cons 七{ cout << "ellipse: :draw()" << endl; 第18章运行时类型识别385 下载 } static int quantity() { return count; } }; int ellipse::count = O; class circle: public ellipse { void operator=(circle&); // Disallow protected: static int count; public: circle() { count++; } circle(cons 七circle&) { count++; } 一circle() { count--; } void draw() const { cout << "circle: :draw()" << endl; } static in七quantity() { return count; } } ; int circle::count = 0; main() { 七stash<shape> shapes; time_t t; II Seed random number generator: srand((unsigned)time(&t)); const mod= 12; for(int i = 0; i < rand() 令mod; i++) shapes.add(new rectangle); for(int j = O; j < rand() % mod; j++) shapes.add(new ellipse); for(int k = O; k < rand() 兮mod; k++) shapes.add(new circle); int Ncircles = O; int Nellipses = O; int Nrects = O; int Nshapes = O; for(int u = O; u < shapes.count(); u++) { shapes[u]->draw(); if(dynamic_cast<circle*>(shapes[u])) Ncircles++; if(dynamic_cast<ellipse*>(shapes[u])) Nellipses++; if(dynamic_cast<rectangle*>(shapes[u])) Nrects++; 对于这个例子,两种方法都是可行的,但静态数据成员方法只能用于我们拥有源代码并已 安装了静态数据成员和成员函数时(或者开发商已为我们提供了这些),另外RT T I可能在不同 的类中用法不同。 18.3 语法细节 本节详细介绍RT T I的两种形式是如何运行的以及两者之间的不同。 18.3.1 对于内部类型的typeid() 为了保持一致性, t y p e i d ( )也可以运用于内部类型,所以下面的表达式结果为t r u e: 18.3.2 产生合适的类型名字 t y p e i d ( )必须在所有的状况下都可以运行,比方说,下面的类中包含了一个嵌套类: 386 C + +编程思想 下载 } if(dynamic_cast<shape*>(shapes[u])) Nshapes++; cout << endl << endl <<"circles=• << Ncircles << endl <<"ellipses=• << Nellipses << endl << "rec 七angles="<< Nrects << endl <<"shapes="<< Nshapes << endl << endl << "circle: :quantity() =• << circle: :quantity() << endl << "ellipse: :quantity() = " << ellipse: :quantity() << endl << "rectangle: :quantity() =" << rectangle: : quantity () << endl << "shape: :quantity() =• << shape: :quantity() << endl;

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值