C++编程艺术

                                   C++编程艺术

                                 

漫游世界——C++概述

     19世纪80年代初期美国AT&贝尔实验室Bjarne Stroustrup发明并实现了C++,它的面向对象程序设计思想无不使全世界的程序员为之惊呼。由C语言演化而来的C++是一种静态数据类型检查的,支持过程化程序设计、数据抽象、面向对象程序设计等多种程序设计风格的语言。

    由于C++面向对象的思想影响如此重大而深远,导致了纯对象语言JavaC#的出现并迅速成为当今主流编程语言。C++全面兼容C,同时提供了比C更严格、更安全的语法。除了具有运行时的高性能特性外,随着软件代码量和复杂程度的急剧增加,比起JavaC#C++软件工程性的优势越来越来明显。

    C++应用广泛。WindowsLinuxUnix是用C语言写的,上层的高级特性是用C++些的;高安全的中型商用机IBM/400系统是用C++写的;Googlebaidu搜索引擎是用C++写的;Firefox浏览器是用C++写的等。    

简单就是美——正确、简单和清晰第一

1.简单的设计和清晰代码的价值怎么强调都不过分,代码的维护者将因为你编写的代码容易理解而感谢你   而且这个维护者往往就是未来的你。

2.编写程序必须以人为本,计算机第二。

3.软件简单为美的哲理:正确优于速度,简单优于复杂,清晰优于技巧,安全优于不安全。

4.例子一,

        if(a<=b)

            max=b;

        else

            max=a;

 把上面的代码写成下面的形式会更易读一些:max=(a<=b)?b:a;

例子二,为了避免意外地错误使用变量,在最小的作用域里引进变量是一个很好的想法。一个最优雅的应用就是在条件中声明变量。如下所示:

        if(double d=fn(void))

        {

            global/=d;

        }

传递火炬——理解参数传递

1.当一个函数被调用时,将安排好其形式参数所需要的存储,各个形式参数将用对应的实际参数进行初始化。参数传递的语义与初始化的语义完全相同。

2.对于引用参数传递和指针参数传递,若不想修改由这个参数所指的对象,应将相关参数声明为const 以告知读者。例如:

       int strlen(const char*);//求字符串的长度

       Int strcmp(const char*,const char*);//比较字符串

3.请注意,参数传递的语义不同于赋值的语义。

4.文字量、常量和需要转换的参数都可以传递给const&参数,但不能传递给非const的引用参数。允许对const  T&参数进行转换。例如:

       void g(double  &d);

       const double pi=3.14;

       g(pi);//错误

5.对非const引用参数不允许做类型转换,这种规定能帮助我们避免一种由于引入临时量而产生的可笑错误。例如:

       void update(float&i);

       void g(double d,float r)

       {

           update(2.0f);//errorconst参数

           update(r);//OK,传递r

引用

           update(d);//error,要求类型转换

       }

 

扔掉镰刀,试试收割机——用vectorstring代替数组

1.在当今软件中缓冲区溢出和安全缺陷是罪魁祸首。固定长度的数组所带来的愚蠢限制,即使仍在正确的界限内,也是软件开发人员的一大困扰。这些问题中大多数都是使用原始C风格设施(比如内置数组、指针和指针运算以及手工内存管理)代替缓冲区,向量或字符串等高层概念所引起的。使用vector或者string不仅更轻松,而且还有助于编写更安全、伸缩性更好的软件。

2.应用标准设施代替C风格数组,理由如下:

1)他们能够自动管理内存。不再需要“比任何长度更长”的固定缓冲区,也不再需要胡乱进行内存重新分配和指针调整。

2)它们具有丰富的接口,可以轻松明确地实现复杂功能。

3)它们与C的内存模型兼容。Vectorstring::c_str都可以传递给C语言的API

4)它们能够提供更大范围的检查。标准设施所能实现的(在调试模式下)迭代器和索引操作符,能够暴露很大范围类型的内存错误。

5)它们支持上述特性并未牺牲太多效率。

6)有助于优化。

3.示例,class phone{

            public:

              string name;//能接受不固定长的名字

              int number;

              void print_phone(){cout<<name<<"  "<<number<<endl;}

        };

        phone phone_book[1000];

        vector<phone> phone_bookvec;

        phone_book[1001].print_phone();//不检查范围

        phone_bookvec.at(1001).print_phone();//检查范围

   上面代码中,内部对象数组phone_book具有固定的规模。如果我们选择了某个很大的规模,那么就会浪费存储;而如果选择一个过小的规模,数组就会溢出。标准库vector就解决了这个问题。

 

重识庐山真面目——运行时类型识别(RTTI)

1.通过RTTI,程序能够使用基类的指针或引用来检索这些指针或引用所指对象的实际派生类型。通过下面两个操作符提供RTTI

(1)dynamic_cast操作符,将基类类型的指针或引用安全地转换为派生类型的指针或引用。

(2)typeid操作符,返回指针或引用所指对象的实际类型。

2.这些操作符只为带有一个或多个虚函数的类返回动态类型信息,对于其他类型,返回静态(即编译时类型的信息。

3.如果绑定到指针的对象不是目标类型的对象,则dynamic_cast失败并返回0;若转换到引用类型dynamic_cast失败,则抛出异常bad_cast ,对于typeid则抛出bad_typeid

4.示例如下,

        class base{virtual void display(){ }};

        Class derived:public base{void display(){ }};

        void fn(base *baseptr)

        {

             if(derived *derivedptr=dynamic_cast<derived*>(baseptr))

                 cout<<"Translated successfully at run time"<<endl;

             else{ }

        }

5.typeid的伪声明为:const type_info&typeid(type_id);

                   const type_info&typeid(expression);

type_info类所提供的基本操作有:

(1) t1==t2(如果两个对象t1t2类型相同,则返回true;否则返回false)

(2) t1!=t2

(3) t.name()  (返回类型名字)

type_info默认构造函数和复制构造函数以及赋值操作符都定义为private,所以不能定义或复制该类型的对象。程序中创建type_info对象的唯一方法是使用typeid

6.typeid示例,

     #include <iostream>

     #include <typeinfo.h>

     using namespace std;

     class Base {public:virtual void vvfunc() {}};

     class Derived : public Base {};

     void main() {

        Derived* pd = new Derived;

        Base* pb = pd;

        cout << typeid( pb ).name() << endl;   //prints "class Base *"

        cout << typeid( *pb ).name() << endl;   //prints "class Derived"

        cout << typeid( pd ).name() << endl;   //prints "class Derived *"

        cout << typeid( *pd ).name() << endl;   //prints "class Derived"

        delete pd;

     }

   

外科医生与助手——体验强大的STL算法

1.STL算法本身就是一种函数模板,算法从迭代器那里获得一个元素。如果把算法想象成一个做手术的外科医生,那么迭代器就是外科医生的助手。当外科医生需要一把手术刀时时候,助手就提供给他;当需要一把剪刀时,助手就递给他。外科医生一心将精力集中在正在进行的手术上,而不是做手术用的器材放到了什么地方或他们放到了哪一种容器中。这样,一个标准的算法就可以处理几乎所有的类型的容器,并且一个容器可以容纳几乎任何类型的元素。这种通用化使得程序员可以无需做任何而外的工作就重复地使用代码和解决方案,花费更少的更少的时间来编写更稳定的程序。

2.排序算法示例, #include<iostream>

                #include<algorithm>//STL算法声明文件

                #include<function>//函数对象类和函数适配器声明文件

                #include<vector>

                using namespace std;

                void main()

{

     int iarray[]={26,17,15,22,23,33,32,40};

     vector>int>ivector(iarray,iarray+sizeof(iarray)/sizeof(int));

     //查找并输出最大元素

     cout<<*max_element(ivector.begin(),ivector.end())<<endl;

     //从小到大稳定排序

     stable_sort(ivector.begin(),ivector.end(),less<int>());

}

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
非常优秀的C++教材,并且附有源码。 目 录 第1章 C++的功能 1 1.1 简洁而丰富的语法 1 1.2 功能强大的库 2 1.3 STL 2 1.4 程序员控制一切 3 1.5 细节控制 3 1.6 运算符重载 3 1.7 一种简洁精练的对象模型 4 1.8 C++发展史 4 第2章 简单的C++垃圾回收器 5 2.1 两种内存管理方法的比较 5 2.1.1 手工内存管理的优缺点 6 2.1.2 垃圾回收的优缺点 6 2.1.3 两种方法都可以使用 7 2.2 在C++中创建垃圾回收器 7 2.3 选择垃圾回收的算法 8 2.3.1 引用计数 9 2.3.2 标记并清除 9 2.3.3 复制 9 2.3.4 采用哪种算法 9 2.3.5 实现垃圾回收器 10 2.3.6 是否使用多线程 10 2.3.7 何时回收垃圾 10 2.3.8 关于auto_ptr 11 2.4 一个简单的C++垃圾回收器 11 2.5 详细讨论GCPtr 23 2.5.1 GCPtr的数据成员 23 2.5.2 函数findPtrInfo() 24 2.5.3 GCIterator typedef 25 2.5.4 GCPtr的构造函数 25 2.5.5 GCPtr的析构函数 26 2.5.6 回收垃圾函数collect() 26 2.5.7 重载赋值运算符 28 2.5.8 GCPtr的复制构造函数 30 2.5.9 指针运算符和转换函数 30 2.5.10 begin()和end()函数 32 2.5.11 shutdown()函数 32 2.5.12 两个实用函数 33 2.6 GCInfo 33 2.7 Iter 34 2.8 如何使用GCPtr 36 2.8.1 处理分配异常 37 2.8.2 一个更有趣的示例 38 2.8.3 对象的分配和丢弃 40 2.8.4 分配数组 41 2.8.5 使用具有类类型的GCPtr 43 2.8.6 一个比较大的演示程序 45 2.8.7 加载测试 51 2.8.8 一些限制 53 2.9 试着完成下面的任务 53 第3章 C++中的多线程 54 3.1 什么是多线程 54 3.2 为什么C++没有内建支持多线程 55 3.3 选用什么样的操作系统和编译器 56 3.4 Windows线程函数概述 56 3.4.1 线程的创建和终止 56 3.4.2 Visual C++对CreateThread()和ExitThread()的替换 57 3.4.3 线程的挂起和恢复 58 3.4.4 改变线程的优先级 59 3.4.5 获取主线程的句柄 60 3.4.6 同步 60 3.5 创建线程控制面板 63 3.5.1 线程控制面板 64 3.5.2 线程控制面板的详细分析 68 3.5.3 控制面板的演示 74 3.6 一个多线程的垃圾回收器 78 3.6.1 附加的成员变量 79 3.6.2 多线程的GCPtr构造函数 79 3.6.3 TimeOutExc异常 81 3.6.4 多线程的GCPtr析构函数 81 3.6.5 gc()函数 82 3.6.6 isRunning()函数 82 3.6.7 gclist的同步访问 83 3.6.8 其他两个改变 83 3.6.9 完整的多线程垃圾回收器 83 3.6.10 多线程垃圾回收器的使用 95 3.7 试着完成下面的任务 97 第4章 C++的扩展 98 4.1 为什么使用译码器 98 4.2 实验性的关键字 99 4.2.1 foreach循环 99 4.2.2 cases语句 100 4.2.3 typeof 运算符 101 4.2.4 repeat/until循环 102 4.3 试验C++新特性的译码器 102 4.4 使用译码器 111 4.5 译码器的运行方式 112 4.5.1 全局声明 112 4.5.2 main()函数 112 4.5.3 gettoken()和skipspaces()函数 114 4.5.4 转换foreach循环 117 4.5.5 转换cases语句 119 4.5.6 转换typeof运算符 121 4.5.7 转换repeat/until循环 122 4.6 演示程序 124 4.7 尝试完成以下任务 130 第5章 Internet文件下载工具 131 5.1 WinINet库 131 5.2 文件下载工具子系统 132 5.2.1 操作的一般理论 137 5.2.2 download()函数 137 5.2.3 ishttp()函数 142 5.2.4 httpverOK()函数 142 5.2.5 getfname()函数 143 5.2.6 openfile()函数 143 5.2.7 update()函数 144 5.3 Download头文件 145 5.4 文件下载工具的演示 145 5.5 基于GUI的下载工具 147 5.5.1 WinDL代码 147 5.5.2 WinDL的运行方式 152 5.6 尝试完成以下任务 153 第6章 使用C++的财务计算 154 6.1 计算贷款的定期偿还 154 6.2 计算投资的预期价值 156 6.3 计算为了获得预期的价值所需的原始投资 157 6.4 为了获得预期的养老金所需的原始投资 159 6.5 计算给定投资所能得到的养老金的最大值 160 6.6 计算贷款余额 162 6.7 尝试完成以下任务 163 第7章 基于AI的问题求解 164 7.1 表示法和术语 164 7.2 组合爆炸 165 7.3 搜索方法 167 7.4 需要解决的问题 167 7.5 FlightInfo结构和Search类 169 7.6 深度优先搜索 171 7.6.1 match()函数 176 7.6.2 find()函数 177 7.6.3 findroute()函数 177 7.6.4 显示路线 179 7.6.5 深度优先搜索分析 179 7.7 广度优先搜索 179 7.8 添加启发信息 182 7.8.1 爬山搜索法 183 7.8.2 爬山法分析 189 7.9 最低成本搜索 189 7.10 寻找多解 190 7.10.1 路径删除 191 7.10.2 节点删除 192 7.11 寻找“最优”解决方案 198 7.12 回到丢失钥匙的问题 204 7.13 尝试完成以下任务 207 第8章 定制STL容器 208 8.1 STL的简要回顾 208 8.1.1 容器 209 8.1.2 算法 209 8.1.3 迭代器 209 8.2 其他的STL实体 209 8.3 定制容器的要求 210 8.3.1 一般要求 210 8.3.2 序列式容器的其他要求 211 8.3.3 关联式容器的要求 211 8.4 创建范围可选的动态数组容器 212 8.4.1 RangeArray的运行方式 212 8.4.2 完整的RangeArray类 213 8.4.3 详细讨论RangeArray类 224 8.4.4 一些RangeArray示例程序 235 8.4.5 尝试完成以下任务 245 第9章 Mini C++解释程序 246 9.1 解释程序和编译器 246 9.2 Mini C++纵览 247 9.3 Mini C++说明 247 9.4 非正式的C++理论 249 9.4.1 C++表达式 250 9.4.2 定义表达式 250 9.5 表达式解析器 252 9.5.1 解析器代码 252 9.5.2 分解源代码 264 9.5.3 显示语法错误 270 9.5.4 表达式求值 271 9.6 Mini C++解释程序 272 9.6.1 main()函数 291 9.6.2 解释程序的预扫描程序 292 9.6.3 interp()函数 295 9.6.4 处理局部变量 297 9.6.5 调用用户自定义的函数 299 9.6.6 给变量赋值 300 9.6.7 执行if语句 302 9.6.8 switch语句和break语句 304 9.6.9 处理while循环 306 9.6.10 处理do-while循环 307 9.6.11 for循环 308 9.6.12 处理cin和cout语句 309 9.7 Mini C++的库函数 311 9.8 mccommon.h头文件 313 9.9 编译并链接Mini C++解释程序 315 9.10 演示Mini C++ 315 9.11 改进Mini C++ 323 9.12 扩展Mini C++ 324 9.12.1 添加新的C++特性 324 9.12.2 添加辅助特性 325

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值