C++文档格式.docx
- 文档编号:17194774
- 上传时间:2022-11-28
- 格式:DOCX
- 页数:36
- 大小:38.48KB
C++文档格式.docx
《C++文档格式.docx》由会员分享,可在线阅读,更多相关《C++文档格式.docx(36页珍藏版)》请在冰豆网上搜索。
1995年,提交了认可DraftStandard(草拟标准)作为标准的申请。
从那时起,它被接受,并且是第一个ANSI/ISOC++Standard。
3楼:
C++随笔-2,封装
封装概念很普遍,类似也可以称之为“包装”。
人要包装,商品要包装,一切的一切都需要包装。
为何会有如此需求呢?
究其原因无非有二,其一是炫耀,其二是遮丑。
经过包装后其价值会有不同程度的提高,这是因为通过包装展现出来的是其最有价值的一面。
另一方面通过包装又可保证其内部具有一定的私密性,这是包装(或封装)的一个相当重要的特性。
现在来考察一下C和C++中的封装。
在C中我们知道有数据结构struct类型,它就是某种程度上对数据的封装。
但仔细看来这种封装只是将一堆相关的数据放在一起,从外面来看并没有多大新意,就内部而言又丝毫没有一点私密性。
所以如此的包装既无从炫耀又无法遮丑。
反过来分析一下C++中的类class类型,它是对“状态机”的封装(或抽象点说就是对“对象”的封装)。
一方面,类似struct类型,class包含有一堆相关的数据(或称状态);
而另一方面其又包含有一堆相关的“处理功能”,合起来正好就是一完美的状态机。
这一点是值得大大地炫耀一下的。
有了其光鲜的外表还不够,class类型还确保了其内部的私密性。
这种私密性在语法层面上保证了软件系统的完整性和安全性,体现了软件工程学中的模块分割原则。
考察一个状态机的封装
我们知道一个状态机若用数学形式表达的话就是:
Y=Fy(X,S)
S=Fs(X,S)
其中Y为输出,X为输入,S为状态。
如果是有限状态机,则S可用有限离散量表示,即S0,S1,…,Sn。
下面给出一个有限状态机的C++程序框架。
注意,这只是对有限状态机数学形式的直接封装。
//有关"
状态机"
的封装
enumstatus_type{S0,S1,S2,S3,S4,…,Sn};
classclass_SM
{
protected:
status_typestatus;
virtualintFy(intx);
virtualvoidFs(intx);
public:
class_SM(void){status=S0;
}
class_SM(status_typeS){status=S;
intDo_it(intx);
~class_SM(){}
};
intclass_SM:
:
Fy(intx)
//returnFy(x,status)
returnx;
}
voidclass_SM:
Fs(intx)
//status<
-Fs(x,status)
Do_it(intx)
intresult;
result=Fy(x);
Fs(x);
returnresult;
这个封装有壳,有头,有尾,还有躯干。
下面就将其解剖一下:
首先是“壳”
由关键字class引入了一个类型class_SM,注意,在C++中同样可以由struct引入一个类型,这在C中是不可以的。
其次来看一下“头”和“尾”
在类中若用类名定义一个函数,则此函数具有特殊的地位,并给它一个称谓——构造函数。
这个特殊的函数就是类的“头”,对象(类的一个实现)的诞生就是由构造函数引领的。
当进入对象所在的作用域时,系统首先分配空间,紧接着就自动调用“合适”的构造函数来初始化整个对象。
在这里我们看到有两个构造函数,它们的形式差异就在于输入参数的不同,由不同参数形式来区分不同函数的调用是C++的另一个重要的特性,在此不作详叙。
下面给出两种不同的对象定义:
class_SMSM;
//调用class_SM(void){status=S0;
class_SMSM(S0);
//调用class_SM(status_typeS){status=S;
在前面可以看到有这样一条定义语句:
它是被放在类的定义“壳”外的,这是因为类的使用者有可能自己决定状态机的初始状态(即调用class_SM(status_typeS){status=S;
})。
若没有这样的选项(即只有第一个构造函数class_SM(void){status=S0;
}),则就可以将定义enumstatus_type{S0,S1,S2,S3,S4,…,Sn}封在类的定义“壳”内,不对外开放。
看过了“头”再看“尾”,在class_SM类中有一个奇怪的函数,就是在类名前加上“~”符号的那个函数,此函数被称之为析构函数。
虽然在此未定义任何具体的操作,但我们从它的调用位置就可以看出它的特殊性。
析构函数是在对象消亡前被系统调用去处理相关后事的那个函数,所以它通常被调用的位置是在即将退出对象所在的作用域时。
这样我们就清楚的知道,对于类的诞生和死亡,系统会自动地调用一些相关的函数去处理某些重要的事情,而这些事情的具体内容是可以由程序设计者来参与的。
这就是类封装的一大特点,且具有相当高的价值。
另外对象还可以“动态”地诞生和消亡(使用对象指针和相关的系统操作),在此仅点到为止。
有了头和尾,当然不能没有躯干。
在此我们所言的躯干就是下列一些成员:
其中status是类型status_type的数据变量,称之为类class_SM的“成员变量”;
而Fy、Fs、Do_it是函数,称之为类class_SM的“成员函数”。
另外要说明的是,前面所提到的构造和析构函数同样是类class_SM的“成员函数”,不过由于这两类函数地位比较特殊,所以给他们另外起了两个特殊的称呼。
一般的成员函数调用是由程序设计者自己显式指定的,并非由系统自动调用。
类封装的私密性
现在我们已经大致的了解了一个类的封装的基本结构和各部份粗略的功能特性。
下面进一步看一下其中有点象标号的那些玩意儿:
pretected:
private:
最后一个虽然未出现,但它却是类的缺省特性(未加说明就是private)。
上面所列的三个东西并非是标号,就单词本身它们是C++的预留关键字,在类中使用它们来说明其下面的成员(包括成员变量和成员函数等)具有相应的被使用权限(注意未加说明则权限就是private)。
由此可见,类封装不仅把它的成员包装了起来,而且限定了使用它们的权限。
缺省情况下,其特性为private(私密的),这样从类的外面就看不见它们,这非常类似于我们日常所说的私密性。
私密性是C++中类封装的又一大特点,它使类这种新的类型更加符合软件工程学中的模块基本准则。
当然如果封装在类中的成员全都是私密的,这将是铁桶一个,毫无意义,就算阿拉伯妇女都会亮出她们那双美丽的眼睛。
为了能把类的光辉炫耀出来,就必须把有使用价值的成员呈现给外界,而这就是有public(公用)来加以说明的。
使用public将改变其下面所列成员的使用权限,使其能被外界存取或调用。
这里还有一个定义使用权限的关键字protected,它与类的继承性有关,在此不阐述。
类的实例化和对象的使用
类被定义以后只是一堆代码(特殊情况下会伴随一些表格),必须将其实例化后才会作为“对象”实实在在的存在,随后被使用。
在此需强调的是“类”不是“对象”,反过来“对象”也不是“类”,它们不是同层次的概念,这有点类似于“类型”和“变量”的关系。
类是产生对象的模子,而对象则是由类这个模具生产出来的产品。
所以一个类可以产生多个对象,这个过程就是类的实例化。
类被实例化后形成的实体——对象,从存储在内存中的形式上看类似于结构(struct),系统为每个对象的所有成员变量分配相应的空间。
每个同类的对象共享它们的成员函数,换句话说就是,类中所定义的代码在实例化过程中并未被复制。
类的实例化过程除了分配空间外还有一件相当重要的事情就是调用构造函数,这是和一般变量或结构类型的实例化具有本质差异的地方。
通过构造函数,对象在被使用之前自动对自己的状态进行初始化,所以对象在诞生之时就已作好了被使用的准备,而一般的变量或结构在引用前必须对其进行赋值。
作为类实例化的产物——对象,一旦诞生就可以被使用。
具体来说,使用对象分两个方面,其一是对其成员变量的赋值或引用(虽然并不建议这样做),其二是调用其成员函数。
关于成员函数的使用存在有几种异化的形式,如对象的“复制”和操作符的“重载”。
在这种变异的情况下,对象仅以其名出现(如出现在表达式内),但实际上只是对它的某一特定的成员函数进行了调用。
相关内容在此不作详表。
现在再回过头来看一下前面定义的状态机,其内有一成员函数intDo_it(intx)。
它是唯一能被外界使用的成员(注意:
构造和析构函数是对象诞生和消亡时由系统调用的)。
沿用前面的实例化语句,相关对象的使用形式为:
Y=SM.Do_it(X);
从上面的调用语句可以看出,Do_it表面上使用了两个参数——X、Y。
但实际上还有一个隐形的参数,就是指向对象SM数据存储区的指针变量——this。
因此可以这么说,就是若成员函数一个参数也没定义的话,也存在着一个指针(this)作为函数的隐形参数。
这就是类封装的“代价”,虽然并不是很大,但毕竟是要付出的。
现在来分析一下为何要有这样一个隐形参数——this,传给成员函数。
就拿前面定义的另外一个成员函数Fs(intx)来看,形式上它只有一个参数x作为输入,但实际上它还要使用类的一个成员变量status。
对于类class_SM的不同对象,成员变量status的地址是不同的。
因此必须将相应对象的成员变量存储区地址传给成员函数,因为成员函数已经知道status的偏移量,所以只要将成员变量存储区的首地址this(这也是对象SM的地址)传给成员函数即可。
4楼:
C++随笔-3,类的嵌套
类的嵌套是指在类定义中含有另外一个类的定义,某种程度上这种嵌在类定义中的类定义可被称之为类的“成员类”。
在类的实例化过程中成员类不会被实例化,只有存在成员类的对象时才会产生相应的对象实例化。
下面给出一个类嵌套的实例
classclass_Outer
classclass_Inner
intinner_x;
class_Inner(void);
class_InnerInner;
intouter_x;
class_Outer();
class_Outer:
class_Inner:
class_Inner(void)
inner_x=10;
class_Outer(void)
this->
Inner.inner_x=20;
outer_x=Inner.inner_x;
class_OuterOuter;
intmain(void)
while
(1)
上例中类class_Inner是在类class_Outer的定义中定义的。
由于前面没有权限设定,所以缺省为private,因此类class_Inner只能在class_Outer的作用域内用来定义对象。
注:
class_Outer的作用域为其定义范围内和成员函数体内。
使用类嵌套的好处在于能将某一类的定义封装在另外一个类的定义之内。
这样一来被封装在内的类定义对外是不可见的,即实现了类定义的“私有化”,这是类封装的私密性在类定义上的拓展。
5楼:
C++随笔-4,静态成员变量和静态成员函数
考察下面的例子:
classclass_A
intx;
staticinta;
staticintadd(inti,intj){return(i+j);
class_A(void){x=10;
a=20;
intget_x(void){returnx;
voidset_x(inti){x=i;
voidset_a(inti){a=i;
voidDo_it(void){x=add(x,a);
intclass_A:
a;
class_AA,B;
intY,Z;
A.set_x(30);
A.set_a(40);
A.Do_it();
B.Do_it();
Y=A.get_x();
Z=B.get_x();
我们发现有两个奇怪的成员和一个奇怪的变量,下面把它们提取出来:
首先分析一下staticinta,这是类class_A的一个成员变量。
特殊的是在变量说明之前加了一个关键字static,这样成员变量a就变成了“静态”的了。
这里静态的意思就是在存储器中分配一个“固定的”存储空间,使类class_A的所有实例化对象中的相应成员变量a都被定位在这个固定的存储空间上,实现了类class_A的所有对象(在此是A和B)共享变量a。
为了表明这个“固定的”存储空间的存在,在全局变量定义中增加了一条相关的定义,即intclass_A:
,而这就是我们看到的那个奇怪的变量。
现在再看看另一个奇怪的成员staticintadd(inti,intj){return(i+j);
},这是类class_A的一个成员函数。
特殊的是在函数说明之前同样加了一个关键字static,这样一来函数add也变成“静态”的了。
在类的封装中我们曾经说过,成员函数有一个隐形指针(this)作为输入参数,这也是封装所付出的代价。
这个代价是否可以避免,若能又可在何种情况下避免呢?
首先来分析一下为何要使用这样一个指针。
我们知道成员函数代码是被类的所有实例化对象所共享的,成员函数只知道所在类的成员地址在对象中的相对偏移量,而不清楚具体对象存储空间的绝对地址。
所以如果要使用所在类的其他成员就必须得到相应对象的地址——this。
但从另一方面来说,如果成员函数不使用所在类中的其他成员,这个对象地址硬传给它不就成多余的吗?
是否存在不用传对象地址的成员函数呢?
回答是肯定的。
前面我们看到的那个变成“静态”的函数恰恰就是我们所要的函数——静态函数。
静态函数和非静态函数的差别就在于是否传递对象指针。
7楼:
C++随笔-5,带有"
constthis"
或"
volatilethis"
的成员函数
先看一下下面的程序:
classexample_class
intget_x(void)const;
intexample_class:
get_x(void)const
return(x);
const关键词都很熟悉,但在这里的使用有点怪。
这里的const并非修饰成员函数的返回值,而是对成员函数的隐含参数this的修饰。
由于传给成员函数的隐含参数是constthis,所以成员函数就不能对由this所指定的本对象内任何成员变量进行修改。
由此可以看到,如果某成员函数不对本对象的成员变量进行修改,利用向成员函数传具有常量特性的this指针可以在语法层面上确保不会对成员变量的修改。
类似的也可以用volatile来修饰this指针(用volatile替代const),这样一来相应的一些优化将被取消。
9楼:
C++随笔-6,类的复制
谈到类的复制涉及到两方面的含义,其一是类的初始复制,其二是类的赋值复制。
具体看下列程序:
classcopy_example
copy_example(void){x=0;
};
copy_example(intx0){x=x0;
copy_example(copy_example&
ref);
copy_example:
copy_example(copy_example&
ref)
x=ref.x;
先看初始复制:
copy_exampleExample1(100);
//Example1.x<
-100
copy_exampleExample2=Example1;
//Example2.x<
-Example1.x
上面有两个定义,第一个定义了对象Example1,并将x初始化成100;
第二个定义了对象Example2,并将对象Example1的成员变量x复制到Example2的成员变量x上。
这样一来Example2的成员变量x的值也为100。
看过了初始复制,再看赋值复制:
-100
copy_exampleExample2;
-0
Example2=Example1;
第二个定义了对象Example2,并将x初始化成0。
在定义之下有一条赋值语句。
由于未对赋值符重载定义(关于重载以后再论),所以其“缺省”语义就是将对象Example1的全部内容原封不动的复制到Example2上。
10楼:
C++随笔-7,为朋友开个后门(友元)
在阐述类的封装时,曾经强调过私密性。
但有时也会对特定对象开个后门(注意:
这有别于共用性),这样有利于特定对象间或对象与特定函数间的联系。
下面给出相关的两个例子:
friendclassclass_B;
//class_Bisafriend
class_A(void){x=100;
classclass_B
inty;
class_AA;
intget_x(void){returnA.x;
class_BB;
intz;
intmain(void)
z=B.get_x();
由于在类class_A中声明了类class_B是其友元(用关键词friend),所以在类class_B中,对象A(cla
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- C+