函数原型与头文件
数据声明与作用域
类、对象、构造函数与析构函数
输入 /输出
函数、参数传递与函数返回值
函数重载与操作符重载
友元函数与内联函数
结构、联合与类
模板类
函数原型
prototype#include "iostream.h"#include "utility.h"
#include "life.h"
void main( )
{ void instructions( );
……
} 包括 iostream的
所有内容
包含函数
user_says_yes()
的原型声明包含类 Life的原型声明
函数 instructions( )
的原型声明
★ 头文件名字的后缀用,.h”表示,程序文件名
字的后缀用,.c”或,.cpp”表示。
★ iostream.h:是 C++输入输出流库的所有类
定义,其中有虚基类 io、输出类 ostream(提
供向流中插入数据的有关操作 )、输入类
istream (提供从流中提取数据的有关操作 )。
cout 是 ostream 类的对象 (实例 );而
cin 是 istream 类的对象 (实例 ) 。
★可通过,# include,定向到该原型的声明文
件,
取得对原型的访问性。
C++的数据声明
C++的数据声明将数据名与数据类型联系起来
其主要形式有:
?常数值:如 25,13.4,“value is”,它们的
内容保持不变。
?变量:数据类型的实例,在程序执行时可以
改变其内容。
?常量:数据声明时在变量名前冠以保留字
const,如 const int maxrow = 20,可定
义 一个常量。其内容在声明时给定,在声
明它的程序运行时不能再赋值。
?枚举:是声明一个整型常数序列的方式。例
如,在程序开头做如下声明
enum Boolean { False,True }
则建立一个 Boolean类型。 False,True 都
是 Boolean类型整型常数,默认值 0 和 1。
?指针:存放对象的存储地址,例如
int i = 5;
int *np; //
np = &i; //把整型变量 i 的地址赋给它
//np 成为指向整型变量 i 的指针
int k = *np; //k中存入 np所指地址 i的内容
?枚举:是声明一个整型常数序列的方式。例如,
在程序开头做如下声明
enum Boolean { False,True }
则建立一个 Boolean类型。 False,True 都是
Boolean类型整型常数,默认值 0 和 1。
?指针:存放对象的存储地址,例如
int i = 5; int *p,*q;
p = &i; q=p;
int k = *p;
p,q为一个
指向整型量
的指针
把整型变量 i
的地址赋给它
k中存入 p所指
地址的内容
相当于 k=i
指针 p的值赋给
指针 q与 p都指向
?引用:它用来给一个对象提供一个替代的名字。
例如 int i = 5; int& j = i;
引用类型
j 代表 i 的一个替代名。当 I(j) 的值改变时,
j(i)的值也跟着改变。我们来看一个简单例子。
void main()
{int I = 7,&j= i;
cout<<"i= "<<i<<“j= "<<j<<endl;
cout<<"i= "<<++i;
cout<<" j= "<<j<<endl;
cout<<"j= "<<++j;
cout<< <<" i= "<<i<<endl;
}
i= 7 j= 7i= 8 j= 8
j= 9 i= 9
C++的作用域
?在 C++中,每个变量都有一个作用域。区分一个变
量时要同时考虑变量名及其作用域。
?在函数定义中声明的变量,仅能在该函数内部有效
使用。
?在类定义中声明的变量,仅能在该类内部有效使用。
?在一个段中声明的名字,也仅能在该段及其子段中
有效使用。
?在整个程序各处都能访问的变量叫做全局变量。如
果一个全局变量在文件 1中声明,在文件 2中使用,
那么在文件 2中必须使用保留字 extern对该变量进
行声明。
?如果一个段中的局部变量与一个全局变量同名,且
还要在此段中使用该全局变量,此时需利用域操
作符,:访问该全局变量。
C++的类
? C++的核心部分是类的定义。类定义体现了抽象数
据类型的思想。为达到信息隐蔽的原则。规定对
类的成员有三级存取:
? 共 (公 )有 (public)
? 私有 (private)
? 保护 (protected)
?在 public 域中声明的数据成员和函数成员 (成员函
数 ),程序中其它类的对象或操作都能请求该类的
对象执行它们,因此这些数据成员和成员函数构
成类的界面(也有书称为接口 interface)部分。
?在 private域和 protected域中声明的数据成员和成
员函数构成类的私有部分,只能由该类的对象和
成员函数,以及声明为友元 (friend)的函数或类的
对象才能访问它们。
?在 protected域中声明的数据成员和成员函数,还
允许该类的派生类访问它们;
?在 private域中声明的数据成员和成员函数,则不允
许该类的派生类访问它们。
?下面给出一个 point 类的声明。 Point 类中 点的表
示由两个整数变量 x,y 组成。类的用户不能直接
访问它们。
class Point
{ private,//私有域
int x; //数据成员:点坐标
int y;
public,//共有域
Point ( int,int ); //构造函数
Point ( Point & ); //复制构造函数
~Point ( ); //析构函数
int get_x ( ); //取 x坐标
int get_y ( ); //取 y坐标
Point operator + ( point ); //点加点
Point operator / ( int ); //点除整数
Point operator * ( int ); //点乘整数
int operator > ( Point ); //点比较
int operator < ( Point ); //点比较
int operator == ( Point& ); //点比较
friend istream& operator >>
( istream&,Point& ); //输入友元函数
friend ostream& operator <<
( ostream&,Point& ); //输出友元函数
};
?为了存取一个点的 x,y分量,类提供了两个函数
get_x,get_y。这样可用 private域来保护数据
的表示,防止类的用户直接使用数据的内部表示
来编写代码,通过使用存取函数来操作数据来
维持类的抽象性。
? private是声明默认的存取级别。
?系统开发时,把类的声明放在头文件中,成员函
数的实现放在源程序文件中。在源程序文件中
函数的实现通过作用域设定命令,::”而被归属
到某一个类。
例,对于 Point类的输出 友元 函数的实现可以在源程
序文件中给出,形为:
ostream & operator << (ostream& strm,Point p)
{ return strm << "(" << p.get_x ( )
<< "," << p.get_y () << ")";
} 把点 p的值以,(x,y)”的格式送到 strm指明
的输出流中去
? 建立类的对象 (亦称为实例化 )时采用的方式类
似于定义 C变量的方式,可以自动地,或静态
地,或通过动态分配来建立。建立一个 Point
类实例的语句是:
? Point p (6,3); 自动地
? Point q; 自动地
? static Point s (3,4); 静态地
? Point *t = new Point(1,1); 通过动态分配
? 对象 p,q和 s都是 Point类的对象。
构造函数
? 当遇到以上的每一个语句时,将隐式地调用
一个构造 (constructor)函数,这个构造函
数属于一个与它同名的类。
? 在 Point类的定义中声明了两个构造函数,构
造函数的参数用于初始化表达式的值。
? 例如,当使用声明 Point p(6,3) 建立 Point
类的对象 p 时,调用了构造函数 Point (int,
int);通过以下函数定义,将其 x,y分量设定
为 6,3:
Point,,Point (int a,int b) { x = a; y = b; }
Point,,Point (int a,int b), x(a),y(b) { }
? 构造函数可以定义默认值。例如
Point,,Point ( int a = 0,int b = 0 )
,x(a),y(b) { }
? 当定义实例时给定初始值,则该实例以给
定初始值来初始化其数据成员
Point p(6,3);
则有 x = a = 6,y = b = 3
? 当定义实例时未给出初始值。则该实例
以默认值来初始化其数据成员
Point q;
则有 x = a = 0,y = b = 0
析构函数
? 当要放弃对象时,需隐式地调用另一个函数,
叫做析构 (destructor)函数,它属于名字相同
的类,但在名字前面加上了一个“~”。例

~ Point。
? 为一个类可定义几个构造函数,但只能定义
一个析构函数。当控制要退出自动变量的作
用域时,或当通过 delete 命令释放一个动
态分配的变量时,就要调用析构函数。当
main函数执行结束时,将释放静态声明的
变量。
? 一个析构函数用于在删除一个类的对象时做
清除工作。
C++的输入 /输出
? 在 C++中执行输入 /输出操作,需用 #include
预处理指令包括一个 <iostream.h>头文件。
用它可支持 C++的流 (stream)操作。
?,流”是个简单的字符序列。在 C++中有两
个预定义的类 istream和 ostream,它们定
义了输入流和输出流。
? 基本输入 /输出方式:
? 键盘屏幕输入 /输出
? 文件输入 /输出
键盘屏幕输入 /输出
? 在 C中有用于定向到键盘输入设备、屏幕输
出设备和错误文件的命令 stdin,stdout和
stderr。
? 在 C++中用 cin,cout和 cerr来定义键盘输
入类、屏幕输出类和错误信息输出类。
? 操作符 << 用于写出类 ostream的一个对象,
对于一系列输出对象,可用 <<分开。
? 操作符 >> 用于读入类 istream的一个对象 。
? 在下面程序中使用了流 cin >>,相继从标准
输入设备上输入两个整型变量 a和 b,并将它
们打印到标准输出设备上。
? 在输出语句中最后输出的 endl是 C++的 I/O操
作符,它的用途是输出一个换行符并清空流。
#include <iostream.h>
void main ( )
{ int a,b;
cin >> a >> b;
cout <<,a, " << n << "f, " << f << endl;
}
? C++中的输入 /输出可以是自由格式,程序
员不需要使用格式化符号来指定输入 /输出
项的类型和顺序。
? 与其它 C++操作符一样,输入 /输出操作符
能够被重载。
文件输入 /输出
? C++中的文件输入 /输出方式如下所示。
? 在程序开头必须用预处理指令 #include包
含头文件 <fstream.h>,它定义了类
ifstream,ofstream和 fstream。
? 要创建一个 输入流,必须声明它为 ifstream
类的实例
? 要创建一个 输出流,必须声明它为
ofstream类的实例
? 执行输入和输出操作的流 必须声明它为
fstream类的实例
#include <fstream.h>
#include <iostream.h>
#include <stdlib.h>
void main ( ) {
ifstream inFile; //inFile为输入流对象
ofstream outFile; //outFile为输出流对象
outFile.open ( "my.dat",ios,,out );
//建立输出文件 ?my.dat?
char univ[ ] = ?Tsinghua?,name[10];
int course = 2401,number;
outFile << univ << endl; //输出到 ?my.dat?
outFile << course << endl;
inFile.open("my.dat",ios::out | ios::nocreate);
//打开输入文件 ?my.dat?
if ( !inFile ) {
cerr <<,不能打开 my.dat”<< endl;
exit(1);
}
char c;
inFile >> name >> c >> number;
outFile << "name," << name << endl;
outFile << "number," << number << endl;
}
C++中的函数
? 在 C++中有两种函数:
常规函数和成员函数
? 不论哪种函数,其定义都包括 4 个部分, 函
数名、形式参数表、返回类型和函数体。
? 函数的使用者通过函数名来调用该函数;
调用时把实际参数传送给形式参数表作为
数据的输入;通过函数体中的处理程序实
现该函数的功能;最后得到返回值作为输
出。
? 下面给出一个函数的例子 。 max是函数名,
int a 和 int b 是形式参数表,函数名前面的
int 是返回类型,在花括号内括起来的是函
数体,它给出了函数操作的实现 。
int max ( int a,int b ) {
//函数返回 a 与 b 中的大值
if (a > b) return a;
else return b;
}
? 在 C++中所有函数都有一个返回值, 或者
返回计算结果, 或者返回执行状态 。
? 如果函数不需要返回值,可使用 void 来表
示它的返回类型。函数的返回值通过函数
体中的 return 语句返回。
? return 的作用是返回一个与返回类型相同
类型的值,并中止函数的执行。
? 函数返回时可以通过引用方式,参看下面
程序,此时在函数类型后面加上一 个,&”。
#include <iostream.h>
char& replace(int m);
char s[80] =,Hello There”;
main ( ) {
replace(5) = ?x?; cout << s;
//用 x代替 Hello后面的空格
}
char& replace ( int m ) {
return s[m];
}
? 函数 replace( )的返回类型说明为返回一个
字符的引用类型,在函数执行时返回参数 m
指定的 s数组元素的值。 main ( )执行时把
字符, x” 送给 s[5]。
C++中的参数传递
? 函数调用时传送给形参表的实参必须与形
参在类型、个数、顺序上保持一致。
? 参数传递有两种方式。一种是传值,这是
缺省的参数传递方式 ; 一种是引用类型。
? 使用传值方式时,把实参的值传送给函数
局部工作区相应的副本中,函数使用这个
副本执行必要的功能。这样,函数修改的
是副本的值,实参的值不变。
? 使用引用类型方式传递时,需将形参声明为
引用类型, 即在参数名前加一个, &”。 参
看下面的程序示例 。
? 当一个实参与一个引用型形参结合时, 被
传递的不是实参的值, 而是实参的地址,
函数通过地址存取被引用的实参 。 函数执
行后实参的值将发生改变 。
? 当一个函数的返回值多于一个时,其中一个
可由 return语句返回,其它返回值可使用
引用型参数返回 。
#include <iostream.h>
void swap (int& i,int& j);
main ( ) {
int a = 1,b =2;
cout << "a and b," << a << " " << b <<
"\n";
swap ( a,b );
//调用时实际参数不需要加 &
cout << "a and b," << a << " " << b <<
"\n";
}
void swap ( int& i,int& j ) //对换 i 与 j 的内容
{ int t = j; j = i; i = t; //不需要加 *
}
? 一种特殊的引用调用方式叫做常值引用,其格
式为 const Type& a,其中 Type为参数的数
据类型 。 在函数体中不能修改常值参数 。
? 一种特殊情况是数组参数的传递 。 数组作为形
参可按传值方式声明, 但实际采用引用方式传
递, 传递的是数组第一个元素的地址 。 在函数
体内对形参的数组所做的任何改变都将反映到
作为实参的数组中 。
? 此外, 在参数表中一般按形如 int R[ ] 的形式
声明, 因此需要显式地声明数组的大小 。
? 若传送的值参是一个对象 (作为类的实例 )
时,在函数中就创建了该对象的一个副本。
在创建这个副本时不调用该对象的构造函
数,但在函数结束前要调用该副本的析构
函数撤消这个副本。
? 若采用引用方式传递对象,在函数中不创
建该对象的副本,也不存在最后撤消副本
的问题。但是,通过引用传递的是对象时,
函数对对象的改变将影响调用的对象。
成员函数的返回值
? 当成员函数的返回值为 传值方式 时,允许改
变该对象的私有数据成员。
? 当成员函数的返回值为 常值传值方式 时,需
加 const 标识,该对象的私有成员不能改变。
? 当成员函数的返回值为引用方式时,该成员
函数的返回值应是一个已存在变量 (或对象 )
的别名。当该成员函数被重新赋值时,其对
应变量 (或对象 )的值将改变。
? 当成员函数的返回值为常值引用方式时,其
返回值与引用方式的成员函数返回值类同。
但该成员函数不能改变该对象的私有成员。
? 当成员函数返回值为常值传值方式或常值引用方
式时,const 标识符一般放在最后。
#include<iostream.h>
class Temperature
{ private:
float highTemp,lowTemp; //数据成员
public:
Temperature(int hi,int lo) //构造函数
{ highTemp = hi; lowTemp = lo; }
void UpdateTemp(float temp); //传值返回
float GetHighTemp( ) const; //常值返回
float GetLowTemp( ) const; //常值传值返回
};
void Temperature,,UpdateTemp(float temp)
{ if (temp > highTemp) highTemp = temp;
if (temp < LowTemp) LowTemp = temp;
}
float Temperature,,GetHighTemp( ) const
{ return highTemp; }
float Temperature,,GetHighTemp( ) const
{ return highTemp; }
C++中的函数重载
? 重载概念体现了面向对象程序设计的多态性 。
? 在同一作用域内, 共享同名的函数称为函数重
载, 实际上就是以相同的名字定义几个不同实
现的函数, 可以是成员函数, 也可以是非成员
函数 。 但是, 定义重载函数时有 — 个限制, 即
被重载的函数至少在参数的个数或参数的类型
上有所不同 。 这样, C++编译器通过检查调用
中的参数个数, 类型和顺序来选择相应的函数 。
C++的操作符重载
? 在 C++中程序员可以 把运算符和用户自定义
的类型一起使用,虽然 C++不允许建立新的
运算符,但允许程序员 重新定义已有的运算
符, 使其在用于类的对象时具有新类型要求
完成的特定的操作,这就是所谓的 运算符重
载 。运算符重载从一个方面体现了 OOP技术
的多态性。
? 运算符重载是通过编写 operator函数来实现
的。该函数具有两种形式:成员函数形式和
友元函数形式。这两种形式都可以访问类中
的私有 (private)成员。
⑴ 运算符重载为类的成员函数
一般格式:
type class_name::operator@ ( <arg_list> )
{ <func_body> }
其中,type为函数的返回值, 也就是运算符的运算
结果值; class_name为该运算符重载所属类的类名
:而@即为所重载的运算符 。
当运算符重载为类的成员函数时, 左边 的操作数
必须是运算符重载所属类的一个 对象 ( 或该类对象
的 引用 ) ;对于一元运算符来说是一个没有参数的
非 static函数;对于二元运算符而言, 是一个带有一
个参数的非 static函数 。 例 1,p1+p2,把两个点 (x1,
y1)和 (x2,y2)相加成一个点 (x1+x2,y1+y2)。
Point Point::operator=(const Point& obj)
{ x=obj.x,y=obj.y;
return *this;
}
Point operator+ (point& p)
{ x += p.x; y += p.y;
return *this;
}
如果有声明,Point p(6,3),q(2,5),r;
我们可以写,r = p + q;
这时输出 p和 r都是,(8,8)
赋值运算符重载
二元运算符 +重载
例 2,p1<p2,两个点 p1和 p2的“小于”关系,表
示 p1比 p2更靠近原点 (0,0)。
int Point::operator<(Point p)
{ return (x*x+y*y) - (p.x*p.x+p.y*p.y); }
友元 (friend)函数
?在类的声明中可使用保留字 friend 定义友元函数
?友元函数实际上并不是这个类的成员函数,它可以
是一个常规函数,也可以是另一个类的成员函数。
如果想通过这种函数存取类的私有成员和保护成员
,则必须在类的声明中给出函数的原型,并在该函
数原型前面加上一个 friend
我们前面给出的 Point类的定义,有两个重载操作
符 << 与 >>,它们都被声明为友元函数。
ostream& operator<<(ostream& strm,Point& p)
{ return strm<<"("<<p.x<<","<<p.y<< ") "; }
私有成员 私有成员
内联 (inline)函数
?在函数定义前加上一个 inline前缀就成为内联函数。
编译程序在编译时将会把这个函数语句直接插入到普
通代码中,因而减少了与函数调用和参数传递有关的
系统开销。
?直接插入代码所需要的空间比不直接插入的调用方
式所需要的空间要多,这取决于函数定义的大小。
C++ 扩充了 C 中结构 (struct) 型的功用,加进成员
函数以说明一个类 (class)。在 C++ 中 struct 与
class 的区别 在于,
?在 struct 中,默认 的访问级别是 public。若在
struct 内部自始至终缺省访问级别,则所有的成员
都是共有的。
?在 class 中,缺省 的访问级别是 private。
?除此之外,struct 与 class 是等价的。
例如,下面给出定义矩形类的两种等价的类声明。
结构 (struct)与类
class Rectangle
{ int x1,y1,h,w;
public:
Rectangle ( );
~Rectangle ( );
int GetX ( );
int GetY ( );
void SetX (int x);
void SetY (int y);
int GetHeight ( );
int GetWidth ( );
…………
};
私有成员
struct Rectangle
{
Rectangle ( );
~Rectangle ( );
int GetX ( );
int GetY ( );
void SetX (int x);
void SetY (int y);
int GetHeight ( );
int GetWidth ( );
…………
private:
int x1,y1,h,w;
};
联合 (Union)与类
与结构一样,用 Union也可以定义类。
?在 C++中,Union可包含函数和变量,还可包含
构造函数和析构函数。
? C++的 Union保留了所有 C的特性,主要是让所
有的数据成员共享相同的存储地址。
?与 class和 struct相比,Union可节省存储。与结
构相似,Union中默认存取级别是 public。
模板 (template)
模板是 C++最强大的特性之一,是 C++
的软件复用的功能之一。
定义, 适合多种数据类型的类定义或
算法,在特定环境下通过简单地代换,
变成针对具体某种数据类型的类定义
或算法 (也可以称为参数化类 )。
用 模板 定义用于排序的数据表类
#include <iostream.h>
template <class Type>
class dataList
{ private:
Type *Element;
int ArraySize;
void Swap (int m1,int m2);
int MaxKey (int low,int high); 保留字
类参数名
public:
dataList (int size = 10), ArraySize (size),
Element (new Type [Size]) { }
~dataList ( ) {delete [ ] Element;}
void Sort ( );
friend ostream& operator << (ostream&
outStream,datalist<Type>& outList);
friend istream& operator >> (istream&
inStream,datalist<Type>& inList);
} ;
类中所有操作作为模板函数实现
#include,datalist.h”
template <class Type>
void dataList <Type>,,Swap (int m1,int m2)
{ //交换由 m1,m2为下标的数组元素的值
Type temp = Element [m1];
Element [m1] = Element [m2];
Element [m2] = temp;
}
使用模板的选择排序算法的主函数
#include,selecttm.h”
const int SIZE = 10;
int main ( )
{
dataList <int> TestList (SIZE);

}