一:前言
C++是对C的继承,由面向过程的的程序设计语言引入面向对象的特色,创造了万物皆对象的理念。引用The_C++._Programming_Language这本书的一段话:C++是一种通用程序设计语言,特别是面向系统程序设计,它——是一个更好的C,支持数据抽象,支持面向对象的程序设计,支持通用型程序设计。
C++开始于过程式程序设计,在它的基础上引入面向对象的范型,使用类层次结构,而后采用模板的通用型程序设计,每一个范型都是在前者的基础上构造起来的。
在开始学习C++的时候,不必纠结于它的语言细节和特色,这里要强调的是设计方法和组织程序的方式,这个阶段里,掌握什么东西可以用C++来做的基本思想,远比怎样做要更明智。
二:过程式程序范型
过程式程序设计语言的典型就是C了,它规划了计算机程序的每一个步骤,例如去倒一杯水的步骤:
main() { stand_up(); go_to_the_table(); prepare_a_cup(); pick_up_the_kettle(); execute_the_pouring_water_action(); while(/*the water is full*/) stop(); pick_up_the_cup(); go_back(); }
这里的每一步都详细的描述了,具体程序设计范型是:确定需要用到哪些过程,选择需要的算法。
面对程序规模越来越大的情况,对数据的组织就显得很重要了。一个相关的过程和所操作的数据组织集合在一起,通常被称为一个模块,程序设计的范型就变成了:确定需要用到哪些模块,将程序分为一些模块,将数据隐藏在模块中(数据隐藏原理)——模块程序范型
三:模块程序设计
模块化程序设计的典型例子是定义一个堆栈,如在用户界面中,可以按如下方式声明和使用:
namespace Stack{ / / interface void push(char) ; char pop() ; } void f() { Stack: :push(´c´) ; if(Stack: :pop() != ´c´) error("impossible") ; }
namesapce是C++特有的命名空间,在这个空间里的成员在使用的时候需要用到::运算符(域运算符),如在使用Stark::push()时,表明了push()函数来自Stark名字空间,与其他使用不会造成干扰。
Stark的定义可用在其他单独编译的部分中提供:
namespace Stack{//implementation const int max_size=200; char v[max_size]; int top=0; void push(charc){/*check for overflow and push c*/} char pop(){/*check for underflow and pop*/} }
这样就实现了用户界面和数据的分离,用户在使用Stark时,不必知道Stark的具体实现细节,只要知道如何使用就行了。
异常处理:
当程序规模不断增大,特别是库的广泛使用,处理错误就显得很重要了。
拿上面的例子来说,当向堆栈中放入过多的字符,堆栈就会溢出,而程序就析崩瓦解了,这里就需要Stark的实现者预先构建异常处理代码,向用户报错,这样就能使用户采取恰当的行动去维护了。
C++ 异常处理涉及到三个关键字:try、catch、throw。
- throw: 当问题出现时,程序会抛出一个异常。这是通过使用 throw 关键字来完成的。
- catch: 在您想要处理问题的地方,通过异常处理程序捕获异常。catch 关键字用于捕获异常。
- try: try 块中的代码标识将被激活的特定异常。它后面通常跟着一个或多个 catch 块。
namespace Stack{//interface void push(char); char pop(); class Overflow{};//type representing overflow exceptions }
void Stack::push(char c) { if(top==max_size)throw Overflow(); //push c }
void f() { //... try{//exceptions here are handled by the handler defined below while(true) Stack::push(´c´); } catch(Stack::Overflow){ //oops:stack overflow;take appropriate action } //... }
以上三段代码,提供了C++标准的异常处理机制:在用户界面定义一个溢出异常的类型;当检测出一个溢出,则抛出一个Overflow的异常;try 块中放置可能抛出异常的代码(try 块中的代码被称为保护代码),catch 块跟在 try 块后面,用于捕获异常(您可以指定想要捕捉的异常类型,这是由 catch 关键字后的括号内的异常声明决定的)。
四:数据抽象
像上面介绍的模块形式,对于清晰的表示复杂的系统而言是远远不够的。本节展示一种用户定义类型的形式。
定义类型的模块:
如果我们希望有许多堆栈,可以这样实现:
namespace Stack{ struct Rep;//definition of stack lay out is elsewhere typedef Rep& stack; stack create();//make a new stack void destroy(stacks);//delete s void push(stacks,char c);//push c onto s char pop(stacks);//pop s }
声明一个Rep结构类型;
这里需要注意的是&关键词的使用:typedef Rep& Stark,确定Stark是对Rep这个名字的引用,也就是Rep的别名。
一个Stack::stack用起来很像内部类型的例子:
struct Bad_pop{}; void f() { Stack::stack s1=Stack::create();//make a new stack Stack::stack s2=Stack::create();//make another new stack Stack::push(s1,´c´); Stack::push(s2,´k´); if(Stack::pop(s1)!=´c´) throw Bad_pop(); if(Stack::pop(s2)!=´k´)throw Bad_pop(); Stack::destroy(s1); Stack::destroy(s2); }
用户定义类型(抽象数据类型):
程序设计范型:确定需要的类型,为每个类型提供完整的一组操作。
class complex{ double re,im; public: complex(double r,double i){re=r;im=i;}//construct complex from twos calars complex(double r){re=r;im=0;}//construct complex from one scalar complex(){re=im=0;}//default complex:(0,0) friend complex operator+(complex,complex); friend complex operator(complex,complex);//binary friend complex operator(complex);//unary friend complex operator*(complex,complex); friend complex operator/(complex,complex); friend bool operator==(complex,complex);//equal friend bool operator!=(complex,complex);//not equal //... };
complex operator+(complex a1,complex a2) { return complex(a1.re+a2.re,a1.im+a2.im); }
void f(complex z) { complex a=2.3; complex b=1/a; complex c=a+b*complex(1,2.3); //... if(c!=b)c=( b/a)+2*b; }
以上complex类实现了对运算符的重载,对复数加、减、乘、除、等于、不等于进行了重新定义。
具体类型:
像上面complex的类型就可以成为具体类型,与抽象类型相对应。
抽象类型:
One property was lost in the transition from S t a c k as a ‘‘fake type’’ implemented by a module
to a proper type.The representation is not decoupled from the user interface;
rather, it is a part of what would be included in a program fragment using S t a c k s.
The representation is private, and therefore accessible only through the member functions, but it is present.
If it changes in any significant way, a user must recompile.
This is the price to pay for having concrete types behave exactly like builtin types.
In particular, we cannot have genuine local variables of a type without knowing the size of the type’s representation.
For types that don’t change often, and where local variables provide muchneeded clarity and efficiency, this is acceptable and often ideal.
However, if we want to completely isolate users of a stack from changes to its implementation, this last S t a c k is insufficient.
Then, the solution is to decouple the interface from the representation and give up genuine local variables.
五:面向对象的程序设计
引入了类
六:通用型程序设计
引入了模板,STL
关于五六两节我并没有详细的展开,原因是这两节是C++的核心部分,所以我把他们放在我后续的博客里面,至此,C++概览就此结束,在今后的学习我将继续更新学习C++的相关细节。
来源:https://www.cnblogs.com/garbslife/p/12252431.html