C++语法学习笔记

C++语法学习笔记

摘取部分重点章节内容
在一个类中包含两种成员: 数据和函数,分别称为数据成员和成员函数。在C++中把一组数据和有权调用这些数据的函数封装在一起,组成一种称为“类(class)”的数据结构。在上面的程序中,数据成员num,score和成员函数setdata,display组成了一个名为Student的“类”类型。成员函数是用来对数据成员进行操作的。也就是说,一个类是由一批数据以及对其操作的函数组成的。
具有“类”类型特征的变量称为“对象”(object)。

1.3 C++程序的构成和书写形式

) 一个C++程序可以由一个程序单位或多个程序单位构成。每一个程序单位作为一个文件。在程序编译时,编译系统分别对各个文件进行编译,因此,一个文件是一个编译单元。
) 一个C++程序总是从main函数开始执行的,而不论main函数在整个程序中的位置如何。
1.4 C++程序的编写和实现
一个程序从编写到最后得到运行结果要经历以下一些步骤。

  1. 用C++语言编写程序
    用高级语言编写的程序称为“源程序”(source program)。C++的源程序是以.cpp作为后缀的(cpp是c plus plus 的缩写)。
  2. 对源程序进行编译
    为了使计算机能执行高级语言源程序,必须先用一种称为“编译器(complier)”的软件(也称编译程序或编译系统),把源程序翻译成二进制形式的“目标程序(object program)”。
    编译是以源程序文件为单位分别编译的。目标程序一般以.obj或.o作为后缀(object 的缩写)。编译的作用是对源程序进行词法检查和语法检查。编译时对文件中的全部内容进行检查,编译结束后会显示出所有的编译出错信息。一般编译系统给出的出错信息分为两种,一种是错误(error);一种是警告(warning) 。
  3. 将目标文件连接
    在改正所有的错误并全部通过编译后,得到一个或多个目标文件。此时要用系统提供的“连接程序(linker)”将一个程序的所有目标程序和系统的库文件以及系统提供的其他信息连接起来,最终形成一个可执行的二进制文件,它的后缀是.exe,是可以直接执行的
    在这里插入图片描述

2.4 C++的运算符

C++的运算符十分丰富,使得C++的运算十分灵活方便。例如把赋值号(=)也作为运算符处理,这样,a=b=c=4就是合法的表达式,这是与其他语言不同的。C++提供了以下运算符:
(1) 算术运算符
+(加)-(减) (乘) /(除) %(整除求余)++(自加) --(自减)
(2) 关系运算符
>(大于)<(小于) ==(等于)>=(大于或等于)<=(小于或等于)!=(不等于)
(3) 逻辑运算符
&&(逻辑与) ||(逻辑或) !(逻辑非)
(4) 位运算符
<<(按位左移) >>(按位右移) &(按位与) |(按位或) ∧(按位异或) ~(按位取反)
(5) 赋值运算符 (=及其扩展赋值运算符)
(6) 条件运算符 (?😃
(7) 逗号运算符 (,)
(8) 指针运算符 (
)
(9) 引用运算符和地址运算符 (&)
(10) 求字节数运算符(sizeof)
(11) 强制类型转换运算符( (类型) 或类型( ))
(12) 成员运算符 (.)
(13) 指向成员的运算符 (->)
(14) 下标运算符 ([ ])
(15) 其他 (如函数调用运算符())
在本章中主要介绍算术运算符与算术表达式,赋值运算符与赋值表达式,逗号运算符与逗号表达式,其他运算符将在以后各章中陆续介绍。

3.1 面向过程的程序设计和算法

在面向过程的程序设计中,程序设计者必须指定计算机执行的具体步骤,程序设计者不仅要考虑程序要“做什么”,还要解决“怎么做”的问题,根据程序要“做什么”的要求,写出一个个语句,安排好它们的执行顺序。怎样设计这些步骤,怎样保证它的正确性和具有较高的效率,这就是
一个面向过程的程序应包括以下两方面内容:
(1) 对数据的描述。在程序中要指定数据的类型和数据的组织形式,即数据结构(data structure)。
(2) 对操作的描述。即操作步骤,也就是算法(algorithm)。
对于面向过程的程序,可以用下面的公式表示:
程序=算法+数据结构
作为程序设计人员,必须认真考虑和设计数据结构和操作步骤(即算法)。
算法是处理问题的一系列的步骤。算法必须具体地指出在执行时每一步应当怎样做。
C++既支持面向过程的程序设计,又支持面向对象的程序设计。无论面向过程的程序设计还是面向对象的程序设计,都离不开算法设计。
C++程序结构
在这里插入图片描述

3.3 赋值语句

前面已介绍,赋值语句是由赋值表达式加上一个分号构成。
(1)C++的赋值语句具有其他高级语言的赋值语句的功能。但不同的是: C++中的赋值号“=”是一个运算符,可以写成
a=b=c=d;
而在其他大多数语言中赋值号不是运算符,上面的写法是不合法的。

3.4 C++的输入与输出

输入和输出并不是C++语言中的正式组成成分。C和C++本身都没有为输入和输出提供专门的语句结构。输入输出不是由C++本身定义的,而是在编译系统提供的I/O库中定义的。
C++的输出和输入是用“流”(stream)的方式实现的。图3.2和图3.3表示C++通过流进行输入输出的过程。
在这里插入图片描述
在这里插入图片描述
3.4.1 输入流与输出流的基本操作
cout语句的一般格式为
cout<<表达式1<<表达式2<<……<<表达式n;
cin语句的一般格式为
cin>>变量1>>变量2>>……>>变量n;

4.1 概述

在一个程序文件中可以包含若干个函数。无论把一个程序划分为多少个程序模块,只能有一个main函数。程序总是从main函数开始执行的。在程序运行过程中,由主函数调用其他函数,其他函数也可以互相调用。在C语言中没有类和对象,在程序模块中直接定义函数。可以认为,一个C程序是由若干个函数组成的,C语言被认为是面向函数的语言。C++面向过程的程序设计沿用了C语言使用函数的方法。在C++面向对象的程序设计中,主函数以外的函数大多是被封装在类中的。主函数或其他函数可以通过类对象调用类中的函数。无论是C还是C++,程序中的各项操作基本上都是由函数来实现的,程序编写者要根据需要编写一个个函数,每个函数用来实现某一功能。因此,读者必须掌握函数的概念以及学会设计和使用函数。
“函数”这个名词是从英文function翻译过来的,其实function的原意是“功能”。顾名思义,一个函数就是一个功能。
在实际应用的程序中,主函数写得很简单,它的作用就是调用各个函数,程序各部分的功能全部都是由各函数实现的。主函数相当于总调度,调动各函数依次实现各项功能。

4.2.1 定义无参函数的一般形式
定义无参函数的一般形式为
类型标识符 函数名([void])
{声明部分
语句

定义有参函数的一般形式为
类型标识符 函数名(形式参数表列)
{声明部分
语句

例如:
int max(int x,int y) //函数首部,函数值为整型,有两个整型形参
{int z; //函数体中的声明部分
z=x>y?x:y; //将x和y中的大者的值赋给整型变量z
return (z); //将z的值作为函数值返回调用点

C++要求在定义函数时必须指定函数的类型

4.3 函数参数和函数的值

4.3.1 形式参数和实际参数
在调用函数时,大多数情况下,函数是带参数的。主调函数和被调用函数之间有数据传递关系。前面已提到:在定义函数时函数名后面括号中的变量名称为形式参数(formal parameter,简称形参),在主调函数中调用一个函数时,函数名后面括号中的参数(可以是一个表达式)称为实际参数(actual parameter,简称实参)。
有关形参与实参的说明:
(1) 在定义函数时指定的形参,在未出现函数调用时,它们并不占内存中的存储单元,因此称它们是形式参数或虚拟参数,表示它们并不是实际存在的数据,只有在发生函数调用时,函数max中的形参才被分配内存单元,以便接收从实参传来的数据。在调用结束后,形参所占的内存单元也被释放。
(2) 实参可以是常量、变量或表达式,如max(3, a+b);但要求a和b有确定的值。以便在调用函数时将实参的值赋给形参。
(3) 在定义函数时,必须在函数首部指定形参的类型
4.3.2 函数的返回值
(1) 函数的返回值是通过函数中的return语句获得的。return语句将被调用函数中的一个确定值带回主调函数中去。
return语句后面的括号可以要,也可以不要。return后面的值可以是一个表达式。
(2) 函数值的类型。既然函数有返回值,这个值当然应属于某一个确定的类型,应当在定义函数时指定函数值的类型。
(3) 如果函数值的类型和return语句中表达式的值不一致,则以函数类型为准,即函数类型决定返回值的类型。对数值型数据,可以自动进行类型转换

4.4 函数的调用

4.4.1 函数调用的一般形式
函数名([实参表列])
如果是调用无参函数,则“实参表列”可以没有,但括号不能省略。如果实参表列包含多个实参,则各参数间用逗号隔开。实参与形参的个数应相等,类型应匹配(相同或赋值兼容)。实参与形参按顺序对应,一对一地传递数据。但应说明,如果实参表列包括多个实参,对实参求值的顺序并不是确定的

4.4.2 函数调用的方式
按函数在语句中的作用来分,可以有以下3种函数调用方式:
1. 函数语句
把函数调用单独作为一个语句,并不要求函数带回一个值,只是要求函数完成一定的操作。如例4.1中的printstar( );
2. 函数表达式
函数出现在一个表达式中,这时要求函数带回一个确定的值以参加表达式的运算。如c=2*max(a,b);
3. 函数参数
函数调用作为一个函数的实参。如
m=max(a,max(b,c)); //max(b,c)是函数调用,其值作为外层max函数调用的一个实参

4.5 内置函数

调用函数时需要一定的时间和空间的开销。图4.5表示函数调用的过程:
在这里插入图片描述

C++提供一种提高效率的方法,即在编译时将所调用函数的代码直接嵌入到主调函数中,而不是将流程转出去。这种嵌入到主调函数中的函数称为内置函数(inline function),又称内嵌函数。在有些书中把它译成内联函数。
指定内置函数的方法很简单,只需在函数首行的左端加一个关键字inline即可。

4.6 函数的重载

在编程时,有时我们要实现的是同一类的功能,只是有些细节不同。例如希望从3个数中找出其中的最大者,而每次求最大数时数据的类型不同,可能是3个整数、3个双精度数或3个长整数。程序设计者往往会分别设计出3个不同名的函数,其函数原型为:
int max1(int a,int b, int c); //求3个整数中的最大者
double max2(double a,double b,double c); //求3个双精度数中最大者
long max3(long a,long b,long c); //求3个长整数中的最大者
C++允许用同一函数名定义多个函数,这些函数的参数个数和参数类型不同。这就是函数的重载(function overloading)。即对一个函数名重新赋予它新的含义,使一个函数名可以多用。
重载函数除了允许参数类型不同以外,还允许参数的个数不同。

4.7 函数模板

C++提供了函数模板(function template)。所谓函数模板,实际上是建立一个通用函数,其函数类型和形参类型不具体指定,用一个虚拟的类型来代表。这个通用函数就称为函数模板。凡是函数体相同的函数都可以用这个模板来代替,不必定义多个函数,只需在模板中定义一次即可。在调用函数时系统会根据实参的类型来取代模板中的虚拟类型,

#include
using namespace std;
template //模板声明,其中T为类型参数
T max(T a,T b,T c) //定义一个通用函数,用T作虚拟的类型名
{if(b>a) a=b;
if(c>a) a=c;
return a;
}

int main( )
{int i1=185,i2=-76,i3=567,i;
double d1=56.87,d2=90.23,d3=-3214.78,d;
long g1=67854,g2=-912456,g3=673456,g;
i=max(i1,i2,i3); //调用模板函数,此时T被int取代
d=max(d1,d2,d3); //调用模板函数,此时T被double取代
g=max(g1,g2,g3); //调用模板函数,此时T被long取代
程序第3~8行是定义模板。定义函数模板的一般形式为
template < typename T> 或 template
通用函数定义 通用函数定义
在建立函数模板时,只要将例4.5程序中定义的第一个函数首部的int改为T即可。即用虚拟的类型名T代替具体的数据类型。在对程序进行编译时,遇到第13行调用函数max(i1,i2,i3),编译系统会将函数名max与模板max相匹配,将实参的类型取代了函数模板中的虚拟类型T。
它只适用于函数的参数个数相同而类型不同,且函数体相同的情况,如果参数的个数不同,则不能用函数模板。
6.2.1 定义指针变量
定义指针变量的一般形式为
基类型 *指针变量名;
下面都是合法的定义:
float *pointer_3; // pointer_3是指向单精度型数据的指针变量
char *pointer_4; // pointer_4是指向字符型数据的指针变量

int i,j; //定义整型变量i,j
int pointer_1, pointer_2; //定义指针变量pointer_1,pointer_2
第2行开头的int是指: 所定义的指针变量是指向整型数据的指针变量。也就是说,指针变量pointer_1和pointer_2只能用来指向整型数据(例如i和j),
使一个指针变量指向另一个变量:只需要把被指向的变量的地址赋给指针变量即可。例如:
pointer_1=&i; //将变量i的地址存放到指针变量pointer_1中
pointer_2=&j; //将变量j的地址存放到指针变量pointer_2中
6.2.2 引用指针变量
有两个与指针变量有关的运算符:
(1) &取地址运算符。
(2) 指针运算符(或称间接访问运算符)。
例如: &a为变量a的地址,p为指针变量p所指向的存储单元。
(3) 指向数组元素的指针变量也可以带下标,如p[i]与
(p+i)等价。
根据以上叙述,引用一个数组元素,可用以下方法:
(1) 下标法,如a[i]形式;
(2) 指针法,如
(a+i)或
(p+i)。其中a是数组名,p是指向数组元素的指针变量。如果已使p的值为a,则
(p+i)就是a[i]。可以通过指向数组元素的指针找到所需的元素。

6.3 数组与指针

6.3.1 指向数组元素的指针
int a[10]; //定义一个整型数组a,它有10个元素
int *p; //定义一个基类型为整型的指针变量p
p=&a[0]; //将元素a[0]的地址赋给指针变量p,使p指向a[0]
在C++中,数组名代表数组中第一个元素(即序号为0的元素)的地址。因此,下面两个语句等价:
p=&a[0];
p=a;
在定义指针变量时可以给它赋初值:
int *p=&a[0]; //p的初值为a[0]的地址
也可以写成
int *p=a; //作用与前一行相同
6.3.3 多维数组与指针
6.5 函数与指针
6.5.1 用函数指针变量调用函数
指针变量也可以指向一个函数。一个函数在编译时被分配给一个入口地址。这个函数入口地址就称为函数的指针。可以用一个指针变量指向函数,然后通过该指针变量调用此函数。

指向函数的指针变量的一般定义形式为
函数类型 (*指针变量名)(函数形参表);
可以用一个指针变量指向max函数,然后通过该指针变量调用此函数。定义指向max函数的指针变量的方法是:
int (*p) (int,int);
p所指向的函数的形参类型
p是指向函数的指针变量
指针变量p指向的函数的类型
请将它和函数max的原型作比较
int max(int,int); //max函数原型
可以看出: 只是用(*p)取代了max,其他都一样。

6.6 返回指针值的函数

一个函数可以带回一个整型值、字符值、实型值等,也可以带回指针型的数据,即地址。其概念与以前类似,只是带回的值的类型是指针类型而已。返回指针值的函数简称为指针函数。
定义指针函数的一般形式为
类型名 *函数名(参数表列);
例如
int *a(int x,int y);

6.7 指针数组和指向指针的指针

6.7.1 指针数组的概念
如果一个数组,其元素均为指针类型数据,该数组称为指针数组,也就是说,指针数组中的每一个元素相当于一个指针变量,它的值都是地址。一维指针数组的定义形式为
类型名*数组名[数组长度];
例如
int *p[4];
6.7.2 指向指针的指针
指向指针数据的指针,简称为指向指针的指针。
怎样定义一个指向指针数据的指针变量呢?如下:
char *(*p);
*运算符的结合性是从右到左,因此“char *(*p);”可写成
char **p;

6.8.1 有关指针的数据类型的小结
在这里插入图片描述
6.8.2 指针运算小结
(1) 指针变量加/减 一个整数
例如: p++,p–,p+i,p-i,p±i,p-=i等。
(2) 指针变量赋值
将一个变量地址赋给一个指针变量
p=&a; //将变量a的地址赋给p
p=array; //将数组array首元素的地址赋给p
p=&array[i]; //将数组array第i个元素的地址赋给p
p=max; //max为已定义的函数,将max的入口地址赋给p
p1=p2; //p1和p2都是同类型的指针变量,将p2的值赋给p1

6.9 引用

对一个数据可以使用“引用”(reference),这是C++对C的一个重要扩充,引用是一种新的变量类型,它的作用是为一个变量起一个别名。假如有一个变量a,想给它起一个别名b,可以这样写:
int a; //定义a是整型变量
int &b=a; //声明b是a的引用
以上语句声明了b是a的引用,即b是a的别名。经过这样的声明后,a或b的作用相同,都代表同一变量
注意: 在上述声明中,&是引用声明符,并不代表地址。不要理解为“把a的值赋给b的地址”。声明变量b为引用类型,并不需要另外开辟内存单元来存放b的值。b和a占内存中的同一个存储单元,它们具有同一地址。声明b是a的引用,可以理解为: 使变量b具有变量a的地址。
6.9.3 引用作为函数参数
有了变量名,为什么还需要一个别名呢?C++之所以增加引用类型, 主要是把它作为函数参数,以扩充函数传递数据的功能。
当看到&a这样的形式时,怎样区别是声明引用变量还是取地址的操作呢?当&a的前面有类型符时(如int &a),它必然是对引用的声明;如果前面无类型符(如cout<<&a),则是取变量的地址

7.1.5 指向结构体变量的指针
一个结构体变量的指针就是该变量所占据的内存段的起始地址。可以设一个指针变量,用来指向一个结构体变量,此时该指针变量的值是结构体变量的起始地址。

{struct Student //声明结构体类型student
{ int num;
string name;
char sex;
float score;
};
Student stu; //定义Student类型的变量stu
Student *p=&stu; //定义p为指向Student类型数据的指针变量并指向stu
stu.num=10301; //对stu中的成员赋值
C++提供了指向结构体变量的运算符->,例如p->num表示指针p当前指向的结构体变量中的成员num。p->num 和(*p).num等价。同样,p->name等价于(*p).name
以下3种形式等价:
① 结构体变量.成员名。如stu.num。
② (*p).成员名。如(*p).num。
③ p->成员名。如p->num。“->”称为指向运算符
第3篇 基于对象的程序设计

  1. 先声明类类型,然后再定义对象
    前面用的就是这种方法,如
    Student stud1,stud2; //Student是已经声明的类类型
    在C++中,声明了类类型后,定义对象有两种形式。
    (1) class 类名 对象名
    如 class Student stud1,stud2;
    把class和Student合起来作为一个类名,用来定义对象。
    (2) 类名 对象名
    如 Student stud1,stud2;
    直接用类名定义对象。这两种方法是等效的。第1种方法是从C语言继承下来的,第2种方法是C++的特色,显然第2种方法更为简捷方便。

8.3.2 在类外定义成员函数
在前面已经看到成员函数是在类体中定义的。也可以在类体中只写成员函数的声明,而在类的外面进行函数定义。如
class Student
{ public:
void display( ); //公用成员函数原型声明
private:
int num;
string name;
char sex; //以上3行是私有数据成员
};
void Student∷display( ) //在类外定义display类函数
{cout<<″num:″<<num<<endl; //函数体
cout<<″name:″<<name<<endl;
cout<<″sex:″<<sex<<endl;
}
Student stud1,stud2; //定义两个类对象

注意: 在类体中直接定义函数时,不需要在函数名前面加上类名,因为函数属于哪一个类是不言而喻的。但成员函数在类外定义时,必须在函数名前面加上类名,予以限定(qualifed),“∷”是作用域限定符(field qualifier)或称作用域运算符,用它声明函数是属于哪个类的。
如果在作用域运算符“∷”的前面没有类名,或者函数名前面既无类名又无作用域运算符“∷”,如
∷display( ) 或 display( )
则表示display函数不属于任何类,这个函数不是成员函数,而是全局函数,即非成员函数的一般普通函数。

类函数必须先在类体中作原型声明,然后在类外定义,也就是说类体的位置应在函数定义之前,否则编译时会出错。
虽然函数在类的外部定义,但在调用成员函数时会根据在类中声明的函数原型找到函数的定义(函数代码),从而执行该函数。

8.5.3 面向对象程序设计中的几个名词
类的成员函数在面向对象程序理论中被称为“方法”(method),“方法”是指对数据的操作。一个“方法”对应一种操作。
显然,只有被声明为公用的方法(成员函数)才能被对象外界所激活。外界是通过发“消息”来激活有关方法的。所谓“消息”,其实就是一个命令,由程序语句来实现。前面的stud.display( );就是向对象stud发出的一个“消息”,通知它执行其中的display“方法”(即display函数)。上面这个语句涉及3个术语: 对象、方法和消息。stud是对象,display( )是方法,语句“stud.display( );”是消息。
域运算符“∷”,
成员运算符“.”

9.1 构造函数

9.1.1 对象的初始化
如果一个类中所有的成员都是公用的,则可以在定义对象时对数据成员进行初始化。
这种情况和结构体变量的初始化是差不多的,在一个花括号内顺序列出各公用数据成员的值,两个值之间用逗号分隔。但是,如果数据成员是私有的,或者类中有private或protected的成员,就不能用这种方法初始化。
9.1.2 构造函数的作用
C++提供了构造函数(constructor)来处理对象的初始化。构造函数是一种特殊的成员函数,与其他成员函数不同,不需要用户来调用它,而是在建立对象时自动执行。构造函数的名字必须与类名同名,而不能由用户任意命名,以便编译系统能识别它并把它作为构造函数处理。它不具有任何类型,不返回任何值。构造函数的功能是由用户定义的,用户根据初始化的要求设计函数体和函数参数。
using namespace std;
class Time
{public:
Time( ) //定义构造成员函数,函数名与类名相同
{hour=0; //利用构造函数对对象中的数据成员赋初值
minute=0;
sec=0;
}
void set_time( ); //函数声明
void show_time( ); //函数声明
private:
int hour; //私有数据成员
int minute;
int sec;
};
上面是在类内定义构造函数的,也可以只在类内对构造函数进行声明而在类外定义构造函数。
有关构造函数的使用,有以下说明:
(1) 在类对象进入其作用域时调用构造函数。
(2) 构造函数没有返回值,因此也不需要在定义构造函数时声明类型,这是它和一般函数的一个重要的不同之点。
(3) 构造函数不需用户调用,也不能被用户调用。
(4) 在构造函数的函数体中不仅可以对数据成员赋初值,而且可以包含其他语句。但是一般不提倡在构造函数中加入与初始化无关的内容,以保持程序的清晰。
(5) 如果用户自己没有定义构造函数,则C++系统会自动生成一个构造函数,只是这个构造函数的函数体是空的,也没有参数,不执行初始化操作。
9.1.3 带参数的构造函数
可以采用带参数的构造函数,在调用不同对象的构造函数时,从外面将不同的数据传递给构造函数,以实现不同的初始化。构造函数首部的一般格式为
构造函数名(类型 1 形参1,类型2 形参2,…)

9.2 析构函数

析构函数(destructor)也是一个特殊的成员函数,它的作用与构造函数相反,它的名字是类名的前面加一个“~”符号。在C++中“~”是位取反运算符,从这点也可以想到: 析构函数是与构造函数作用相反的函数。
当对象的生命期结束时,会自动执行析构函数。具体地说如果出现以下几种情况,程序就会执行析构函数: ①如果在一个函数中定义了一个对象(它是自动局部对象),当这个函数被调用结束时,对象应该释放,在对象释放前自动执行析构函数。
析构函数的作用并不是删除对象,而是在撤销对象占用的内存之前完成一些清理工作,使这部分内存可以被程序分配给新对象使用。程序设计者事先设计好析构函数,以完成所需的功能,只要对象的生命期结束,程序就自动执行析构函数来完成这些工作。
9.3 调用构造函数和析调用析构函数的次序正好与调用构造函数的次序相反: 最先被调用的构造函数,其对应的(同一对象中的)析构函数最后被调用,而最后被调用的构造函数,其对应的析构函数最先被调用。构函数的顺序

9.5 对象指针

在建立对象时,编译系统会为每一个对象分配一定的存储空间,以存放其成员。对象空间的起始地址就是对象的指针。可以定义一个指针变量,用来存放对象的指针。如果有一个类:
class Time
{public:
int hour;
int minute;
int sec;
void get_time( );
};
void Time∷get_time( )
{cout<<hour<<″:″<<minute<<″:″<<sec<<endl;}
在此基础上有以下语句:
Time *pt; //定义pt为指向Time类对象的指针变量
Time t1; //定义t1为Time类对象
pt=&t1; //将t1的起始地址赋给pt
这样,pt就是指向Time类对象的指针变量,它指向对象t1。
定义指向类对象的指针变量的一般形式为
类名 *对象指针名;
可以通过对象指针访问对象和对象的成员。如
*pt pt所指向的对象,即t1。
(*pt).hour pt所指向的对象中的hour成员,即t1.hour
pt->hour pt所指向的对象中的hour成员,即t1.hour
(*pt).get_time ( ) 调用pt所指向的对象中的get_time函数,即t1.get_time
pt->get_time ( ) 调用pt所指向的对象中的get_time函数,即t1.get_time

9.11 类模板

可以声明一个通用的类模板,它可以有一个或多个虚拟的类型参数,
template //声明一个模板,虚拟类型名为numtype
class Compare //类模板名为Compare
{public:
Compare(numtype a,numtype b)
{x=a;y=b;}
numtype max( )
{return (x>y)?x:y;}
numtype min( )
{return (x<y)?x:y;}
private:
numtype x,y;
};
(1) 声明类模板时要增加一行
template <class 类型参数名>
(2) 原有的类型名int换成虚拟类型参数名numtype。在建立类对象时,如果将实际类型指定为int型,编译系统就会用int取代所有的numtype,如果指定为float型,就用float取代所有的numtype。这样就能实现“一类多用”。
由于类模板包含类型参数,因此又称为参数化的类。如果说类是对象的抽象,对象是类的实例,则类模板是类的抽象,类是类模板的实例。利用类模板可以建立含各种数据类型的类。
使用方法:
可以这样声明和使用类模板:
(1) 先写出一个实际的类。由于其语义明确,含义清楚,一般不会出错。
(2) 将此类中准备改变的类型名(如int要改变为float或char)改用一个自己指定的虚拟类型名(如上例中的numtype)。
(3) 在类声明前面加入一行,格式为
template<class 虚拟类型参数>,如
template //注意本行末尾无分号
class Compare
{…}; //类体

如果 try 代码块中发生异常,异常被抛给第一个 catch 块

14.1 异常处理

程序中常见的错误有两大类: 语法错误和运行错误。在编译时,编译系统能发现程序中的语法错误。
C++处理异常的机制是由3个部分组成的,即检查(try)、抛出(throw)和捕捉(catch)。把需要检查的语句放在try块中,throw用来当出现异常时发出一个异常信息,而catch则用来捕捉异常信息,如果捕捉到了异常信息,就处理它。
(1) 首先把可能出现异常的、需要检查的语句或程序段放在try后面的花括号中。
(2) 程序开始运行后,按正常的顺序执行到try块,开始执行try块中花括号内的语句。如果在执行try块内的语句过程中没有发生异常,则catch子句不起作用,流程转到catch子句后面的语句继续执行。
(3) 如果在执行try块内的语句(包括其所调用的函数)过程中发生异常,则throw运算符抛出一个异常信息。throw抛出异常信息后,流程立即离开本函数,转到其上一级的函数(main 函数)。
throw抛出什么样的数据由程序设计者自定,可以是任何类型的数据。
(4) 这个异常信息提供给try-catch结构,系统会寻找与之匹配的catch子句。
(5) 在进行异常处理后,程序并不会自动终止,继续执行catch子句后面的语句。
由于catch子句是用来处理异常信息的,往往被称为catch异常处理块或catch异常处理器。
下面讲述异常处理的语法。
throw语句一般是由throw运算符和一个数据组成的,其形式为
throw 表达式;
try-catch的结构为
try
{被检查的语句}
catch(异常信息类型 [变量名])
{进行异常处理的语句}
14.2.2 什么是命名空间
所谓命名空间,实际上就是一个由程序设计者命名的内存区域。程序设计者可以根据需要指定一些有名字的空间域,把一些全局实体分别放在各个命名空间中,从而与其他全局实体分隔开来。如
namespace ns1//指定命名空间ns1
{int a;
double b;
}
如果在程序中要使用变量a和b,必须加上命名空间名和作用域分辨符“::”,如ns1::a,ns1::b。这种用法称为命名空间限定(qualified),这些名字(如ns1::a)称为被限定名(qualified name)。C++中命名空间的作用类似于操作系统中的目录和文件的关系。
命名空间的作用是建立一些互相分隔的作用域,把一些全局实体分隔开来,以免产生名字冲突。
std是C++标准库的命名空间, std 是 standard 的缩写,意思是“标准命名空间”。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值