Upload
roddy
View
132
Download
3
Embed Size (px)
DESCRIPTION
C++ 语言程序设计. 第 5 讲: C++ 程序的结构. 构造函数. 相当于: Clock::Clock() { hour = minute = second = 0; }. 默认参数构造函数. class Clock { public : Clock() : hour(0), minute(0), second(0) {} Clock( int NewH, int NewM=0, int NewS=0); Clock(Clock& c); private : - PowerPoint PPT Presentation
Citation preview
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