第 6章 类与对象
6.1 类与对象
6.2 构造函数与析构函数
6.3 类的组合
6.4 友元
6.5 静态成员
6.6 对象数组与对象指针
6.7 this指针
6.1 类与对象
6.1.1 类与对象的概念对象 (object),是现实世界中的客观事物。
类 (class),是把具有相同属性的事物划分为一类,从而得出的抽象概念。
面向对象程序设计中的 类,是具有相同属性和服务的 一组对象的集合,它为属于该类的全部对象提供了抽象的描述。
对象 是 类的实例,类 是同种 对象的抽象 。
第 6章 类与对象如,确定大小和颜色的矩形都是一个个 具体的对象,而将所有矩形的共同特点抽象出来,就是一个 矩形类 。
这些共有的属性包括 颜色 ( color ),左上角坐标 ( left,top ),长 ( length )和宽 ( width ) 等;
对这些属性的处理包括 改变矩形的颜色 ( SetColor ) 和 大小 ( SetSize ),移动矩形到新的位置 ( Move ),绘出矩形 ( Draw ) 等。将矩形的这些属性和方法作为一个整体,封装在一起形成一个矩形类。
6.1 类与对象
6.1.2 类的声明
class 类名
{
private:
私有数据成员和成员函数;
protected:
保护数据成员和成员函数;
public:
公有数据成员和成员函数;
};
第 6章 类与对象例 6.1 定义一个长方形类 CRect,其数据成员包括颜色,左上角坐标,长和宽,其函数成员包括改变矩形的颜色 (SetColor)
和大小( SetSize),移动矩形到新的位置( Move),绘出矩形( Draw)。
class CRect
{
private:
char color[10];
int left;
int top;
int length;
int width;
public:
void SetColor(char *c);
void SetSize(int l,int w);
void Move(int t,int l);
void Draw();
};
第 6章 类与对象例 6.1 (续一)
void CRect::SetColor(char *c)
{
strcpy(color,c);
}
void CRect::SetSize(int l,int w)
{
length=l;
width = w;
}
void CRect::Move(int t,int l)
{
top = t;
left = l;
}
void CRect::Draw()
{
cout << "矩形左上角坐标为 (" << left << "," << top << ")" << endl;
cout << "矩形长和宽分别为 " << length << "," << width << endl;
cout << "矩形的颜色是 " << color << endl;
}
第 6章 类与对象域运算符(,:)用于指出该函数是哪一个类的成员函数,用法:
类名,:函数名(参数表)
例 6.1 (续二)
void main()
{
CRect r;
r.SetColor("Red");
r.Move(10,20);
r.SetSize(100,200);
r.Draw();
r.Move(50,50);
r.SetColor("Blue");
r.Draw();
}
第 6章 类与对象定义 CRect类的对象,定义对象的格式:
类名 对象名 1,对象名 2,……
访问对象的公有成员,格式为:
对象名,公有成员函数名(参数表)
对象名,公有数据成员名程序运行结果为:
矩形左上角坐标为( 20,10)
矩形长和宽分别为 100,200
矩形的颜色是 Red
矩形左上角坐标为( 50,50)
矩形长和宽分别为 100,200
矩形的颜色是 Blue
6.1 类与对象
6.1.3 成员的访问控制
private,私有访问权限,只允许类中的成员函数访问,其他函数不能访问。
protected,保护访问权限,在第 7章中介绍。
public,公有访问权限,在任何函数中都可以访问。
例:若主函数中有以下语句,是否正确?
CRect r;
strcpy( r.color,“red”);
r.top = 10;
r.left = 20;
第 6章 类与对象在主函数中不能访问类的私有成员
6.1 类与对象
6.1.3 成员的访问控制(续)
若不指定类中的成员的访问权限,则 默认为私有成员 。
类也可以由 struct关键字声明,strust与 class的区别是:如果不指定访问权限,前者缺省的访问权限是公有的,而后者是私有的。用 struct声明前面的矩形类:
struct CRect
{
void SetColor(char *c);
void SetSize(int l,int w);
void Move(int t,int l);
void Draw();
private:
char color[10];
int left;
int top;
int length;
int width;
};
第 6章 类与对象
6.1 类与对象
6.1.4 类的成员函数
1,类成员函数的定义方式
在类外部定义,如前面定义的长方形类的成员函数一般格式为:
函数类型 类名,:成员函数名(参数说明)
{
函数体
}
在类中定义,如
class CRect
{ ……
public:
void setcolor( char *c ){ strcpy( color,c ); }
……
};
第 6章 类与对象
6.1 类与对象
6.1.4 类的成员函数(续一)
2,内联成员函数
将成员函数的定义直接写在类中即成为内联成员函数
在类外定义时用 inline指出:
如,
inline void CRect::SetColor(char *c)
{
strcpy(color,c);
}
第 6章 类与对象
6.1 类与对象
6.1.4 类的成员函数(续二)
3,带默认参数值的成员函数注意,默认参数只能在声明或定义中的一处给出,即如在类中的函数声明已经给出默认参数值:
void SetSize(int l=100,int w=100);
则在函数定义时就不能再给出默认值。
同样如果在定义时给出了默认值:
void CRect::SetSize(int l=100,int w=100)
{
length=l;
width = w;
}
在声明处就不能再给默认值了。
第 6章 类与对象返 回
6.2 构造函数与析构函数构造函数:对对象进行初始化。
析构函数:在对象销毁时进行内存释放等清理工作。
6.2.1 构造函数
1,构造函数的特点
(1) 构造函数的函数名与类名相同。
(2) 不能定义构造函数的类型(即不能指明构造函数返回值的类型)。
(3) 构造函数应声明为公有函数。
(4) 构造函数不能在程序中调用,在对象创建时,构造函数被系统自动调用。
2,构造函数的作用构造函数的作用就是在对象被创建时利用特定的值构造对象,
将对象初始化为一个特定的状态,使此对象具有区别于其它对象的特征。
第 6章 类与对象例 为 CRect类添加构造函数
class CRect
{
private:
char color[10];
……
public:
CRect( );
CRect(char *c,int t,int left,int len,int wid);
void SetColor(char *c);
……
};
CRect::CRect()
{
strcpy(color,"Black");
top = 0;
left = 0;
length = 0;
width = 0;
}
二者是重载函数,在定义对象时,
如果不给出参数,就自动调用第一个构造函数,如果给定 5个参数就自动调用第二个构造函数。
第 6章 类与对象例 为 CRect类添加构造函数(续)
CRect::CRect(char *c,int t,int lef,int len,int wid )
{
strcpy(color,c);
top = t;
left = lef;
length = len;
width = wid;
}
void main()
{
CRect r1; //自动调用第一个构造函数
CRect r2(“red”,10,10,100,100); //自动调用第二个构造函数
CRect r3("green",200,200,50,50); //自动调用第二个构造函数
r1.Draw();
r2.Draw();
r3.Draw();
}
第 6章 类与对象
6.2 构造函数与析构函数
6.2.2 析构函数
1,析构函数的特点
(1) 析构函数名字为符号,~”加类名。
(2) 析构函数没有参数,不能指定返回值类型。
(3) 一个类中只能定义一个析构函数,所以析构函数不能重载。
(4) 当一个对象作用域结束时,系统自动调用析构函数。
如 CRect类的析构函数声明为,~CRect();
定义为,CRect::~CRect()
{ ……
}
2,析构函数的作用在删除一个对象前被调用,释放该对象成员的内存空间,以及其它一些清理工作。
第 6章 类与对象例 6.2 设计一个简单的字符串类,类中有两个数据成员,分别表示字符串的长度和字符串的内容,有一个构造函数和一个析构函数,函数 GetLength( )返回字符串长度,函数
GetContents( )获得字符串的内容,重载函数 SetContents( )给字符串设置值。
#include <iostream.h>
#include <string.h>
class CString
{
private:
int length;
char *contents;
public:
CString(); //构造函数
~CString(); //析构函数
int GetLength();
void GetContents(char *str);
void SetContents(int len,char *cont);
void SetContents(char *cont);
};
第 6章 类与对象例 6.2 (续一)
CString::CString()
{
length = 0;
contents = NULL;
cout << "字符串对象初始化 " << endl;
}
CString::~CString()
{
cout << contents << "被销毁 " << endl;
if(contents != NULL)
delete contents;
}
int CString::GetLength()
{
return length;
}
void CString::GetContents(char *str)
{
strcpy(str,contents);
}
第 6章 类与对象例 6.2 (续二)
void CString::SetContents(int len,char *cont)
{
length = len;
if(contents != NULL)
delete contents;
contents = new char[len+1];
strcpy(contents,cont);
cout << "两个参数的 SetContents函数 " << endl;
}
void CString::SetContents( char *cont)
{
length = strlen(cont);
if(contents != NULL)
delete contents;
contents = new char[length+1];
strcpy(contents,cont);
cout << "一个参数的 SetContents函数 " << endl;
}
第 6章 类与对象重载函数 SetContents( )
都是将要设置的字符串长度赋给数据成员 length,
然后判断原来数据成员
contents是否已经有数据(即已经不为空 NULL
了),如果已不为空,
则先释放原来的内存,
再根据新字符串的长度重新申请内存。
例 6.2 (续三)
void main()
{
CString str1,str2; //两次调用构造函数
str1.SetContents("第一个字符串 "); //调用有一个参数的 SetContents函数
str2.SetContents(20,"第二个字符串两个参数 "); //调用有两个参数的 SetContents函数
int i = str1.GetLength();
char string[100];
str1.GetContents(string);
cout << i << " "<< string << endl;
i = str2.GetLength();
str2.GetContents(string);
cout << i << " " << string << endl;
}
第 6章 类与对象程序运行结果为:
字符串对象初始化字符串对象初始化一个参数的 SetContents函数两个参数的 SetContents函数
12 第一个字符串
20 第二个字符串两个参数第二个字符串两个参数被销毁第一个字符串被销毁
6.2 构造函数与析构函数
6.2.3 拷贝构造函数拷贝构造函数也是构造函数,它的作用是用一个已经存在的对象初始化新对象,拷贝构造函数的参数为该类对象的引用 。
例 6.3 设计一个复数类,两个数据成员分别表示复数的实部
( real) 和虚部 ( imag),三个构造函数分别在不同的情况下初始化对象,函数 Set( ) 设置复数实部和虚部的值,函数 Print( ) 输出复数,函数 Add( ) 和函数 Sub( ) 分别实现复数的加减法运算 。
第 6章 类与对象例 6.3 源程序
#include "iostream.h"
class CComplex
{
private:
double real;
double imag;
public:
CComplex();
CComplex(double r,double i);
CComplex(CComplex &c); //复数类的拷贝构造函数声明
void Set(double r,double i);
void Print();
CComplex Add(CComplex c);
CComplex Sub(CComplex c);
};
第 6章 类与对象例 6.3 源程序(续一)
CComplex::CComplex()
{
real = 0.0;
imag = 0.0;
}
CComplex::CComplex (double r,double i)
{
real = r;
imag = i;
}
CComplex::CComplex (CComplex &c) //复数类的拷贝构造函数定义
{
real = c.real;
imag = c.imag;
}
// 设置复数类的实部和虚部
void CComplex::Set(double r,double i)
{
real = r;
imag = i;
}
第 6章 类与对象例 6.3 源程序(续二)
// 显示复数值
void CComplex::Print()
{
cout << "(" << real << "," << imag << ")" << endl;
}
// 返回两个复数的相加结果
CComplex CComplex::Add(CComplex c)
{
CComplex temp;
temp.real = real + c.real;
temp.imag = imag + c.imag;
return temp;
}
// 返回复数相减的结果
CComplex CComplex::Sub(CComplex c)
{
CComplex temp;
temp.real = real - c.real;
temp.imag = imag - c.imag;
return temp;
}
第 6章 类与对象例 6.3 源程序(续三)
void main(void)
{
CComplex a,b(3.0,4.0),c;
CComplex d(b); //调用复数类的拷贝构造函数
cout << "a = ";
a.Print();
cout << "b = ";
b.Print();
cout << "d = ";
d.Print();
c = b.Add(d);
d = a.Sub(d);
cout << "c = ";
c.Print();
cout << "d = ";
d.Print();
}
第 6章 类与对象程序运行结果为:
a = (0,0)
b = (3,4)
d = (3,4)
c = (6,8)
d = (-3,-4)
返 回
6.3 类的组合类的组合 就是在一个 类中内嵌其他类的对象 作为成员,因为内嵌对象是该类对象的组成部分,当创建该对象时,其内嵌对象也被自动创建。
在 C++中是通过构造函数的初始化表为内嵌对象初始化的。组合类带有初始化表的构造函数的定义格式为:
类名,:构造函数 (参数表 ):内嵌对象 1(参数表 1),内嵌对象 2(参数表 2),…
{
构造函数体
}
组合类构造函数的执行顺序为:
( 1)按内嵌对象的声明顺序依次调用内嵌对象的构造函数。
( 2)然后执行组合类本身的构造函数。
第 6章 类与对象例 6.4 点类 CPoint和线段类 CLine
#include <iostream.h>
#include <math.h>
class CPoint
{
public:
CPoint(int x=0,int y=0)
{
X=x;
Y=y;
cout << " CPoint 构造函数被调用 " << endl;
};
CPoint(CPoint &p);
int GetX()
{
return X;
}
int GetY()
{
return Y;
}
private:
int X,Y;
};
第 6章 类与对象例 6.4 点类 CPoint和线段类 CLine(续一)
CPoint::CPoint(CPoint &p)
{
X = p.X;
Y = p.Y;
cout << " CPoint 拷贝构造函数被调用 " << endl;
cout << "(" << X << "," << Y << ")" << endl;
}
class CLine
{
public:
CLine(CPoint p1,CPoint p2);
float GetDistance();
private:
CPoint start;
CPoint end;
};
第 6章 类与对象例 6.4 点类 CPoint和线段类 CLine(续二)
CLine::CLine(CPoint ps,CPoint pe),start(ps),end(pe)
{
cout << "CLine 构造函数被调用 " << endl;
}
float CLine::GetDistance()
{
double x = double (end.GetX() - start.GetX() );
double y = double (end.GetY() - start.GetY() );
return (float) sqrt(x*x + y*y );
}
void main()
{
CPoint p1(1,1),p2(4,5);
CLine l(p1,p2);
cout << "The distance is,";
cout << l.GetDistance() << endl;
}
第 6章 类与对象程序运行结果为:
CPoint 构造函数被调用
CPoint 构造函数被调用
CPoint 拷贝构造函数被调用
( 4,5)
CPoint 拷贝构造函数被调用
( 1,1)
CPoint 拷贝构造函数被调用
( 1,1)
CPoint 拷贝构造函数被调用
( 4,5)
CLine 构造函数被调用
The distance is,5
例 6.4 点类 CPoint和线段类 CLine(续三)
CLine类的对象 l的构造过程,
第 6章 类与对象
CLine l(p1,p2)
CLine::CLine(CPoint ps,CPoint pe),start(ps),end(pe)
{…}
CPoint::CPoint(CPoint &p)
{…}
( 1)( 2)
( 3) ( 4)
返 回
6.4 友元友元提供了在不同类的成员函数之间、类的成员函数与一般函数之间进行数据共享的机制,友元分为友元函数和友元类。
友元函数,一般函数或类的成员函数友元类,友元类的所有成员函数都自动成为友元函数
6.4.1 友元函数定义友元函数时,只要在函数原型前加入关键字 friend,并将函数原型放在类中,格式为:
friend 类型标识符 友元函数名(参数列表);
友元函数可以是一个普通函数,也可以是其他类的成员函数,
在其函数体中可以通过 对象名直接访问这个类的私有成员 。
第 6章 类与对象例 6.5 定义点类 CPoint,写一个函数计算两点之间的距离。
#include <iostream.h>
#include <math.h>
class CPoint
{
public:
CPoint(int x=0,int y=0);
int GetX();
int GetY();
private:
int X,Y;
};
CPoint::CPoint(int x,int y)
{
X=x;
Y=y;
};
int CPoint::GetX()
{
return X;
}
第 6章 类与对象
int CPoint::GetY()
{
return Y;
}
double GetDistance(CPoint start,CPoint end)
{
int x1,y1,x2,y2;
double d;
x1 = start.GetX();
y1 = start.GetY();
x2 = end.GetX();
y2 = end.GetY();
d = sqrt( (x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) );
return d;
}
void main()
{
CPoint p1(1,1),p2(4,5);
double d;
d = GetDistance(p1,p2);
cout << "The distance is," << d << endl;
}
例 6.5 (续)
将函数 GetDistance()声明为 CPoint类的友元。将 CPoint类修改如下:
class CPoint
{
public:
CPoint(int x=0,int y=0);
int GetX();
int GetY();
friend double GetDistance(CPoint start,CPoint end);
private:
int X,Y;
};
函数 GetDistance()改写如下:
double GetDistance(CPoint start,CPoint end)
{
double d;
d = sqrt( (end.X-start.X)*(end.X-start.X) + (end.Y-start.Y)*(end.Y-start.Y) );
return d;
}
第 6章 类与对象
6.4 友元
6.4.2 友元类如果一个类(如类 A)的很多成员函数都需要经常访问另一个类(如类 B)的私有成员,可以将类 A声明为类 B的友元。
若 A类为 B类的友元类,则 A类的所有成员函数都是 B类的友元函数,都可以访问 B类的私有成员。
声明友元类的语法形式为:
Class B
{
……
friend class A; // 声明 A为 B的友元类
……
};
第 6章 类与对象例 6.6 友元类的使用
#include <iostream.h>
class A
{
private:
int x;
public:
void Display()
{
cout << x << endl;
}
int Getx()
{
return x;
}
friend class B;
};
第 6章 类与对象
class B
{
private:
A a;
public:
void Set(int i);
void Display();
};
void B::Set(int i)
{
a.x=i;
}
void B::Display()
{
cout << a.x << endl;
}
void main()
{
B b;
b.Set(10);
b.Display();
}
程序运行结果为:
10
6.4 友元
6.4.2 友元类(续)
注意:
友元关系是单向的,在上面的例子中,B类是 A类的友元,所以 B类的成员函数可以访问 A类的私有成员,但 A类不是 B类的友元,
A类的成员函数不能访问 B类的私有成员。
友元关系是不能传递的,既如果 A类是 B类的友元,B类是 C类的友元,并不能推断 A类是 C类的友元。
第 6章 类与对象返 回
6.5 静态成员
6.5.1 静态数据成员静态数据成员特点:在 每个类中只有一个拷贝,由该类的所有对象共同维护和使用,从而实现了同一类的不同对象之间的数据共享。
静态数据成员的定义格式:在定义类的成员时前面加 static
static 类型标识符 静态数据成员名;
在类的声明中仅仅对静态数据成员进行引用性说明,必须在文件作用域的某个地方用类名限定进行定义,这时也可以进行初始化,格式如下:
类型标识符 类名,:静态数据成员名 = 初始值;
静态数据成员不属于任何一个对象,可以通过类名直接对它进行访问,一般的用法是:
类名,:静态数据成员名第 6章 类与对象例 6.7 在 CStudent类中添加静态数据成员,保存
CStudent类的对象总数。
#include <iostream.h>
#include <string.h>
class CStudent
{
private:
int number;
char name[10];
static int total;
public:
CStudent(int xh,char *xm);
~CStudent();
int GetTotal();
int GetNumber();
};
第 6章 类与对象
CStudent::CStudent(int xh,char *xm)
{
number = xh;
strcpy(name,xm);
total++;
}
CStudent::~CStudent()
{
total--;
}
int CStudent::GetTotal()
{
return total;
}
int CStudent::GetNumber()
{
return number;
}
例 6.7 (续)
int CStudent::total = 0;
void func();
void main()
{
CStudent s1(10001,"AAAAAA" );
cout << s1.GetNumber() << endl;
cout << s1.GetTotal() << endl;
CStudent s2(10002,"BBBBBB" );
cout << s2.GetNumber() << endl;
cout << s1.GetTotal() << endl;
cout << s2.GetTotal() << endl;
func();
cout << s1.GetNumber() << endl;
cout << s1.GetTotal() << endl;
}
void func()
{
CStudent s3(10003,"CCCCCC" );
cout << s3.GetNumber() << endl;
cout << s3.GetTotal() << endl;
}
第 6章 类与对象程序运行结果为:
10001
1
10002
2
2
10003
3
10001
2
10001
AAAAAA
10002
BBBBBB
10003
CCCCCC
number
name
total
s1 s2 s3
6.5 静态成员
6.5.1 静态数据成员(续)
例 6.7中,若在主函数中使用下面的语句:
cout << CStudent::total << endl;
在编译时就会产生错误信息“不能访问 CStudent类的私有成员”,是由于 total是类的私有静态成员,类外不能直接访问。
如果改写成下面的语句:
cout << CStudent::GetTotal() << endl;
仍然有语法错误,GetTotal()不是静态成员函数,调用非法”。即 不能用类名调用非静态成员函数 。
第 6章 类与对象
6.5 静态成员
6.5.2 静态成员函数静态成员函数,在成员函数声明的前面加上关键字 static。
静态成员函数的特点:
(1) 对于公有的静态成员函数,可以通过类名或对象名来调用,
而一般的非静态成员函数只能通过对象名来调用。静态成员函数可以由类名通过符号,,:”直接调用。
(2) 静态成员函数可以直接访问该类的静态数据成员和静态函数成员,不能直接问非静态数据成员和非静态成员函数。
第 6章 类与对象例 6.8 在 CStudent类中添加静态成员函数
#include <iostream.h>
#include <string.h>
class CStudent
{
private:
int number;
char name[10];
static int total;
public:
CStudent(int xh,char *xm);
~CStudent();
static int GetTotal();
int GetNumber();
};
第 6章 类与对象
CStudent::CStudent(int xh,char *xm)
{
number = xh;
strcpy(name,xm);
total++;
}
CStudent::~CStudent()
{
total--;
}
int CStudent::GetTotal()
{
return total;
}
int CStudent::GetNumber()
{
return number;
}
例 6.8 (续)
int CStudent::total = 0;
void func();
void main()
{
cout << CStudent::GetTotal() << endl;
CStudent s1(10001,"AAAAAA" );
cout << CStudent::GetTotal() << endl;
CStudent s2(10002,"BBBBBB" );
cout << CStudent::GetTotal() << endl;
func();
cout << CStudent::GetTotal() << endl;
}
void func()
{
CStudent s3(10003,"CCCCCC" );
cout << s3.GetTotal() << endl;
}
第 6章 类与对象程序运行结果为:
0
1
2
3
2
可通过类名直接访问静态成员函数,
这样即使未定义 CStudent类的对象,
也可以访问静态数据成员 total了
6.5 静态成员
6.5.2 静态成员函数(续)
注意,在静态成员函数中访问非静态数据成员,或非静态成员函数,都会产生语法错误。
例如,
int CStudent::GetTotal()
{
cout << number;
return total;
}
第 6章 类与对象语法错误,不能在静态成员函数中访问非静态数据成员返 回
6.6 对象数组与对象指针
6.6.1 对象数组对象数组,数组中的每一个元素都是类的对象。
声明一个一维对象数组的语法形式:
类名 数组名 [常量表达式 ];
引用对象数组元素的公有成员:
数组名 [下标 ].成员名;
对象数组的初始化,调用构造函数 对每个元素初始化如:
CStudent s[3] = { CStudent( 10001,"AAAAAA" ),
CStudent( 10002,"BBBBBB" ),
CStudent( 10003,"CCCCCC") };
第 6章 类与对象例 6.9 对象数组的应用
#include <iostream.h>
#include <string.h>
class CStudent
{
private:
int number;
char name[10];
int age;
public:
CStudent(int xh,char *xm,int a);
int GetAge();
};
第 6章 类与对象
CStudent::CStudent(int xh,char *xm,int a)
{
number = xh;
strcpy(name,xm);
age = a;
}
int CStudent::GetAge()
{
return age;
}
例 6.9 (续)
void main()
{
int sum=0;
CStudent s[5] = { CStudent(10001,"AAAAAA",20),
CStudent(10002,"BBBBBB",22 ),
CStudent(10003,"CCCCCC",24 ),
CStudent(10004,"DDDDDD",26 ),
CStudent(10005,"EEEEEE",28 )
};
for(int i=0; i<5; i++)
{
sum += s[i].GetAge();
}
cout << sum/5 << endl;
}
第 6章 类与对象程序运行结果为:
24
6.6 对象数组与对象指针
6.6.2 对象指针对象指针,用于存放对象地址的变量。
声明对象指针的语法形式:
类名 *对象指针名;
例如:
CStudent *p;
CStudent s( 1001,” AAAAAA”,20) ;
p = &s;
通过对象指针访问成员的方法为,
对象指针名 ->成员名第 6章 类与对象例 6.10 通过对象指针访问成员,将例 6.9主函数改写
void main()
{
int sum=0;
CStudent *p[5];
p[0] = new CStudent(10001,"AAAAAA",20);
p[1] = new CStudent(10002,"BBBBBB",22);
p[2] = new CStudent(10003,"CCCCCC",24);
p[3] = new CStudent(10004,"DDDDDD",26);
p[4] = new CStudent(10005,"EEEEEE",28);
for(int i=0; i<5; i++)
{
sum += p[i]->GetAge();
}
cout << sum/5 << endl;
for(i=0; i<5; i++)
{
delete p[i];
}
}
第 6章 类与对象程序运行结果为:
24
返 回
6.7 this指针
this指针,类的每个普通成员函数都有一个隐含的 this指针参数,不需要显示说明。 this指针指向调用该函数的对象。
例:
class CPoint
{
public:
CPoint(int x=0,int y=0);
int GetX();
int GetY();
private:
int x,y;
};
CPoint::CPoint(int x,int y)
{
x=x;
y=y;
};
第 6章 类与对象此处的 x和 y都是函数形参中的 x和 y,
因为参数是局部变量,在函数体中优先访问(同名覆盖),因此此处无法访问到类成员中的 x和 y
可将构造函数改写如下:
CPoint::CPoint(int x,int y)
{
this -> x=x;
this -> y=y;
};
定义该类对象:
CPoint p(10,20);
例 6.11 定义一个二叉搜索树,在树中查找指定节点
#include <iostream.h>
class CTree
{
private:
int value; //节点的值
CTree *left,*right; //节点的左节点指针、右节点指针
public:
CTree(int v);
~CTree();
int GetValue(); //得到节点的值
void add(int v); //向二叉树添加一个节点
CTree *find(int v); //查找值为 v的节点
};
第 6章 类与对象例 6.11 (续一)
CTree::CTree(int v)
{
value = v;
left = NULL;
right = NULL;
}
CTree::~CTree()
{
if(left)
{
delete left;
left = NULL;
}
if(right)
{
delete right;
right = NULL;
}
}
第 6章 类与对象构造函数用参数 v初始化节点的的值,并将其左节点和右节点都置为空。
value
left
right
v
NULL
NULL
析构函数使用递归的方法,将该节点以下的节点全部删除。
例 6.11 (续二)
int CTree::GetValue()
{
return value;
}
void CTree::add(int v)
{
if(v==value) //保证节点的值不重复
return;
else if(v < value) //将小于本节点的值插入左树或左节点
{
if(left != NULL)
left->add(v); //用递归方法将值插入左树
else
left = new CTree(v); //新建一个值为 v的节点作为左节点
}
else
{
if(right != NULL)
right->add(v);
else
right = new CTree(v);
}
}
第 6章 类与对象将某个值插入到二叉树的合适的位置,本例建立的是二叉树搜索树,节点没有重复的值,且该节点左边节点的值都小于该节点的值,该节点右边节点的值都大于该节点的值,仍然使用递归的方法将指定的值插入到合适的位置。
例 6.11 (续三)
CTree* CTree::find(int v)
{
if(v==value)
return this;
else if(v < value)
{
if(left != NULL)
return left->find(v);
else
return NULL;
}
else
{
if(right != NULL)
return right->find(v);
else
return NULL;
}
}
第 6章 类与对象函数 find()也是使用递归的方法在树中查找指定的值,如查到就返回该节点的指针,
否则返回 NULL。因为本函数要返回该节点的指针,因此必须使用 this指针,否则没有办法实现。
例 6.11 (续四)
void main()
{
CTree *root;
root = new CTree(10);
root->add(20);
root->add(2);
root->add(6);
root->add(35);
root->add(15);
CTree *n1,*n2;
n1=root->find(6);
if(n1)
cout << n1->GetValue() << endl;
else
cout << "not found!" << endl;
n2=root->find(7);
if(n2)
cout << n2->GetValue() << endl;
else
cout << "not found!" << endl;
delete root;
}
第 6章 类与对象返 回
10
2 20
6 15 35
程序运行结果为:
6
not found!
谢 谢!