C++语言程序设计
第 5讲,C++程序的结构
构造函数
class Clock {
public,
Clock(), hour(0),minute(0),second(0) {}
Clock(int NewH,int NewM=0,int NewS=0);
Clock(Clock& c);
private,
int hour; int minute; int second;
};
Clock::Clock(int NewH,int NewM,int NewS)
{
hour = NewH; minute = NewM; second = NewS;
}
Clock::Clock(Clock& c)
{
hour = c.hour; minute = c.minute; second = c.second;
}
相当于,Clock::Clock() { hour = minute = second = 0; }
拷贝构造函数
默认参数构造函数
析构函数
class Clock {
public,
Clock();
void SetTime (int,int,int);
void ShowTime();
~Clock(); // 析构函数
private,
int hour; int minute; int second;
char* pbuf;
};
Clock::Clock() { pbuf = new char[128]; }
Clock::~Clock() { delete[] pbuf; }
对象被删除的时刻自动调用
main()
{
Clock c; // 构造
c.SetTime(9,30,30);
} // 析构
?构造函数 可使每个对象都有正确的初始

?析构函数 可使每个对象在结束时自动进
行清理工作
?析构函数的使用
?一个类只能有一个析构函数,不允许重载!
?最先析构的是自动变量;
?静态对象的生命期一直到程序结束;( static)
?全局对象是最后被析构的。
?访问函数和工具函数
?将类的函数分为两大类,访问函数 和 工具函数 。
?访问函数是供客户调用的,一般为 public。
?工具函数是为实现访问函数的某些功能而需要的
函数,一般为 private。
?数据成员和成员函数的使用
?数据一般设为私有成员,便于保护;
?需要用户设置的私有数据成员用 get和 set提供给
用户;
?要保证私有数据成员在任何时候都是有效的。
?接口与实现的分离
?软件工程的一个最基本的原则,接口与实现
分离
?.h文件与,cpp文件分离
?类的定义与类的实现分离
?但是 Java中类的定义与实现是在一起的,Why?
?因为 Java中有一个专门管接口的类叫 Interface。这
个类是公开的,而其他类则被屏蔽起来。
这种方式称为对象的, 包装, 或称, 封
装, 。
?public:,private,( protected,) 都是用来控制
成员函数的作用。
? 类的客户可通过公有成员 (public)知道类提供什么样的服务。
? 类的客户不能直接访问类的私有成员 (private),它们只能
通过成员函数(或友元)来访问。
? C++提倡编写与实现无关的程序。 在类定义中尽量避免写函
数实现的代码。(也不是绝对的,只要觉得可以公开,并以
后不会改动,则可以将实现写到类的定义中)
? [注意 ]在理论上 public:,private,protected,只使用一
次。但现在 C++编译器(如 VC++)可支持多次。而在 Java中每
一个函数前面都要求加上这个说明符。
§ 控制对成员的访问
§ 软件的可重用性
?面向对象的程序设计的一个重要目标就是 软件
的可重用性 。
?可重用性意味着以前的代码可以部分加以利用,
并对其余部分改写,以免整个程序重新编写。
?要实现可重用性,程序必须设计良好、具有较
好的可读性,并预先把需要扩展部分考虑好。
函数原型( prototype)的作用域
?函数原型中的参数,其作用域仅限于声明中。
?例如,设有下列原型声明,
double Area(double radius);
? radius 的作用域仅在于此,不能用于程序正文其他地方,因而
可有可无。可以写成,
double Area(double);
?double Area(double radius=5);
? 可简化成 double Area(double =5);
块作用域
?在块中声明的标识符,其作用域自声明处起,
限于块中,例如,
void fun(int a)
{ int b(a);
cin >> b;
if (b>0)
{
int c;
,....,
}
}
a




b




c




类作用域
?类 X的成员 M具有类作用域,对 M的访问方式如下,
? 如果在 X的成员函数中没有声明同名的局部作用域标
识符,那么在该函数内可以访问成员 M。
class X
{ int M;
public,void fun();
}
void X::fun()
{ M=10;
{ int M=20;
… …
}
cout << M;
}
局部自动变量
类的成员变量

文件作用域
?不在前述各个作用域中出现的声明,具有文件
作用域,这样声明的标识符的作用域开始于声
明点,结束于文件尾。
?全局变量!
int i; // 全局变量,文件作用域
void main()
{ i = 5;
{ int i; // 局部变量,块作用域
i = 7;
cout <<,i=,<< i << endl; // 输出 7
}
cout <<,i=,<< i << endl; // 输出 5
}
例 5-2,变量的生存期与可见性
#include<iostream.h>
void other();
int i=1; // i 为全局变量,具有静态生存期。
int main()
{ static int a;// 静态局部变量,有全局寿命,局部可见。
int b = -10; // b,c为局部变量,具有动态生存期。
int c = 0;
cout <<"---MAIN---\n";
cout <<" i,"<< i <<" a,"<< a <<" b,"<< b << " c,"
<< c << endl;
c = c+8; other();
cout <<"---MAIN---\n";
cout <<" i,"<< i <<" a,"<< a <<" b,"<< b <<" c,"
<< c << endl;
i=i+10; other();
}
void other()
{
static int a=2;
static int b=0;
// a,b为静态局部变量,具有全局寿命,局部可见。
//只第一次进入函数时被初始化。
int c=10; // C为局部变量,具有动态生存期,
//每次进入函数时都初始化。
a=a+2; i=i+32; c=c+5;
cout<<"---OTHER---\n";
cout<<" i,"<< i <<" a,"<< a <<" b,"<< b <<" c,"
<< c << endl;
b=a;
}
运行结果,
---MAIN---
i,1 a,0 b,-10 c,0
---OTHER---
i,33 a,4 b,0 c,15
---MAIN---
i,33 a,0 b,-10 c,8
---OTHER---
i,75 a,6 b,4 c,15
例 5-3:时钟程序
class Clock //时钟类声明
{
public,//外部接口
Clock();
void SetTime(int NewH,int NewM,int NewS);
// 三个形参均具有函数原型作用域
void ShowTime();
~Clock(){}
private,//私有数据成员
int Hour,Minute,Second;
};
//时钟类成员函数实现
Clock::Clock() //构造函数
{
Hour=0;
Minute=0;
Second=0;
}
void Clock::SetTime(int NewH,int NewM,int NewS)
{
Hour=NewH;
Minute=NewM;
Second=NewS;
}
void Clock::ShowTime()
{
cout<<Hour<<":"<<Minute<<":"<<Second<<endl;
}
Clock globClock;//声明对象 globClock,
//具有静态生存期,文件作用域
int main()//主函数
{
cout<<"First time output:"<<endl;
//引用具有文件作用域的对象,
globClock.ShowTime();//对象的成员函数具有类作用域
globClock.SetTime(8,30,30);
Clock myClock(globClock);
//声明具有块作用域的对象 myClock
cout<<"Second time output:"<<endl;
myClock.ShowTime(); //引用具有块作用域的对象
}
程序的运行结果为,
First time output,
0:0:0
Second time output,
8:30:30
静态成员
?静态数据成员
?用关键字 static声明
?该类的所有对象维护该成员的同一个拷贝
?必须在类外定义和初始化,用 (::)来指明所
属的类。
?静态成员函数
?类外代码可以使用类名和作用域操作符来调
用静态成员函数。
?静态成员函数只能引用属于该类的静态数据
成员或静态成员函数。
例 5-4,具有静态数据成员的 Point类
class Point
{
public,
Point(int xx=0,int yy=0)
{ X=xx; Y=yy; countP++; }
Point(Point &p);
int GetX(){return X;}
int GetY(){return Y;}
void GetC()
{ cout <<" Object id = " << countP << endl; }
private,
int X,Y;
static int countP;
};
静态数据成员声明
Point::Point(Point &p)
{ X=p.X;
Y=p.Y;
countP++;
}
int Point::countP=0;
int main()
{ Point A(4,5);
cout<<"Point A,"<<A.GetX()<<","<<A.GetY();
A.GetC();
Point B(A);
cout<<"Point B,"<<B.GetX()<<","<<B.GetY();
B.GetC();
}
静态数据成员初始化
静态成员函数举例
class Application
{ public,
static void f();
static void g();
private,
static int global;
};
int Application::global=0;
void Application::f()
{ global = 5; }
void Application::g()
{ cout << global << endl; }
int main()
{
Application::f();
Application::g();
return 0;
}
友元 friend
?友元是 C++提供的一种破坏数据封装和数
据隐藏的机制。
?通过将一个模块声明为另一个模块的友元,
一个模块能够引用到另一个模块中本是被
隐藏的信息。
?可以使用友元函数和友元类。
?为了确保数据的完整性,及数据封装与隐
藏的原则,建议尽量不使用或少使用友元。
例 5-6,使用友元函数计算两点距离
class Point //Point类声明
{ public,//外部接口
Point(int xx=0,int yy=0) {X=xx;Y=yy;}
int GetX() { return X; }
int GetY() { return Y; }
friend float fDist (Point &a,Point &b);
private,//私有数据成员
int X,Y;
};
float fDist ( Point& a,Point& b )
{
double dx = a.X-b.X;
double dy = a.Y-b.Y;
return (float)sqrt(dx*dx+dy*dy);
}
int main()
{ Point myp1(1.0f,1.0f),myp2(4.0f,5.0f);
cout<<"The distance is,;
cout<< fDist (myp1,myp2) << endl;
return 0;
}
友元类
class A {
friend class B; public,
void Display() { cout << x << endl; }
private,int x;
}
class B { public,
void Set(int i); void Display();
private,A a;
};
void B::Set(int i)
{
a.x = i;
}
void B::Display()
{
a.Display();
}
访问 A的私有成员
但在 A 中不能访问 B 的私有成员。 !!!
常类型 const
?常类型 是只读的意思。
?常类型的对象必须进行初始化,而且不能
被更新。
?常引用,被引用的对象不能被更新。
const 类型说明符 &引用名
?常对象,必须进行初始化,不能被更新。
类名 const 对象名
常对象举例
class A
{
public,
A(int i,int j) { x = i; y = j; }
,.,
private,
int x,y;
};
A const a(3,4); // a是常对象,不能被修改
例 5-8,常成员函数举例
class R
{ public,
R(int r1,int r2){ R1 = r1; R2 = r2; }
void print();
void print() const;
private,
int R1,R2;
};
void R::print()
{ cout<<R1<<":"<<R2<<endl;
}
void R::print() const
{ cout<<R1<<";"<<R2<<endl;
}
int main()
{ R a(5,4);
a.print();
//调用 void print()
const R b(20,52);
b.print();
//调用 void print() const
}
例 5-9,常数据成员举例
class A
{public,
A(int i);
void print();
const int& r;
private,
const int a;
static const int b; //静态常数据成员
};
const int A::b=10;
A::A(int i),a(i),r(a) {}
void A::print()
{ cout<<a<<":"<<b<<":"<<r<<endl; }
int main()
{/*建立对象 a和 b,并以 100和 0作为初值,
分别调用构造函数,通过构造函数的初始化
列表给对象的常数据成员赋初值 */
A a1(100),a2(0);
a1.print();
a2.print();
}
运行结果,
100:10:100
0:10:0
?