1.类的定义
class 类名称
{ private: 数据成员;
成员函数;
protected: 数据成员;
成员函数;
public: 数据成员;
成员函数;
}; //类定义结束 必须有分号“ ;”
class 是保留字, 作用与struct 相同 定义一个结构也叫类。
private(私有), 缺省
protected(保护) ,
public(公有)
都是访问限制
例 计数器类 存储于文件“count.h”中
class counter
{ private: //私有成员
unsigned int value; //数据成员
public: //公有成员
counter( ) { value=0;} //无参构造函数
counter(int x){ if(x>0)value=x;
else value=0;}//有参构造函数
void increment( ){if(value<65535)value++;}
void decrement( ){if(value>0)value--;}
unsigned access_value( ){return value;}
};
2. 对象的定义 object
counter c1, c2; //语句1
counter c3(5); //语句2
语句1定义counter 类的对象c1, c2,即实际变量
(实例)。
对象定义时必须为数据成员赋初值即初始化。初始化由类中的构造函数自动完成。语句1 自动调用 counter 类中无参构造函数,使
c1.value=c2.value=0。
语句2定义对象c3, 自动调用有参构造函数使c3.value=5.
注意:不能使用c1.value为它赋值; 因为 value 在counter类中是私有成员不可见,只能用成员函数来调用。
对象不能直接调用私有成员,只能通过公有成员函数来调用私有成员
对象调用成员函数,叫发一个消息
为c1发消息:
c1.increment( ); //计数器自动加1
c1.decrement( ); // 计数器自动减1
例 计数器测试程序
#include “iostream.h”
#include “count.h”
void main( )
{ counter c1,c2;
for( int i=1; i<=8;i++)
{c1.increment( );
cout<<“ \nc1=” <<c1.access_value( );
c2.increment( ); }
cout<<“ c2=” <<c2.access_value( );
for( i=1; i<=5;i++)
{c2.decrement( );
cout<<“ \nc2=” <<c2.access_value( );
c1.decrement( ); }
cout<<“ c1=” <<c1.access_value( );
}
测试结果
c1=1
c1=2
c1=3
c1=4
c1=5
c1=6
c1=7
c1=8 c2=8
c2=7
c2=6
c2=5
c2=4
c2=3 c1=3
圆的类
class Circle
{ float radius;
public:
Circle(float r=0):radius(r){}//构造函数
float GetRadius( );
float CircleCircum( );
float CircleArea( );
};
成员函数类外定义
Circle:: Circle(float r) //构造函数
{ radius = r; }
float Circle:: GetRadius( )
{ return radius;}
float Circle:: CircleCircum( )
{ return 2*3.14.6*radius; }
float Circle:: CircleArea( )
{ return 3.1416*radius*radius; }
圆类的测试
#include “iostream.h”
#include “circle.h”
void main( )
{ Circle a(3), b(2);
cout<<“Circum of Circle a = ”
<<a.CircleCircum( )<<endl;
cout<<“Area of Circle b = ”
<<b.CircleArea( )<<endl;
}
长方形类
class Rectangle
{ float x, y;
public:
Rectangle(float a=0, float b=0): x(a),y(b)
{ }
float RecCircum( ){return 2*(x+y);}
float RecArea( ){return x*y;}
};
3. 对象指针和对象数组
a. 对象指针
如同定义一个对象一样,用类名可以申明一个对象指针。
例 counter *p,*q;
申明counter 类的指针,指针没有初始化,
调用指针必须先分配内存,或指向一个变量的地址,否则出严重错误,甚至死机。
(1) p=new counter(3);
分配一个整形数据内存,这时系统自动调用有参
构造函数初始化*p的value=3;
(2)q=new counter[3];
分配三个连续整形数据内存,这时系统自动调用无参构造函数初始化
q,q+1, q+2的value都是0。
如果类中没有无参构造函数,语句(2)出错。
确定地址后的对象指针可以调用类中公有数
据及公有函数。
p→increment( );
(q+1) →decrement( );
(*p).decrement( );
(*p).decrement( )中的括号不能省略,因为
运算符 . 的优先级高于*;
对象指针用毕,要予以撤销,释放内存,
delete p; delete[ ] q;
撤销后的指针可以再用,只要重新分配内存或指向一个内存。
b. 对象数组
如果类中有无参构造函数,可以定义对象数组
(3) counter c[3];
这时系统自动调用无参构造函数初始化c[0],c[1],c[2]的value都是0。
如果类中没有无参构造函数,语句(3)出错。
4. 类的数据成员
a. 一个类中的数据成员不可以初始化,
例 class A
{ int value=0;\\出错
.......};
b. 另一个类的对象可以做本类的数据成员,但要先定义后作成员。
只先申明不行。本类对象不可以做自己的数据成员。
c. 指向本类或另一类对象的指针,或引用可以作本类的数据成员。
只要先申明就可以。
d. 公有成员和私有成员的先后次序可以交换。可以把私有成员写在类的前部,也可以写在后部。
e. 本类对象可以调用本类公有数据或公有函数,不能调用私有数据和私有成员。
例 class A;
class B
{ A *p; //合法
A& q; //合法
B * r; //合法
A a; //出错
B b; //出错
};
长方形和圆的类
class RecCircle
{ Rectangle Rec;
Circle Cir;
public:
RecCircle(float a, float b, float c):
Rec(a,b), Cir(c){ }
float Circum( ){return
Rec.RecCircum( )+Cir.CircleCircum( );}
float Area( ){ return
Rec.RecArea( )+Cir.CircleArea( );
};
5. 类的 成员函数
成员函数也叫类所具有的方法或操作。
函数头叫方法的界面,也叫消息模式。
函数可以重载(要求参数不同)不必用overload。
可以类内申明类外定义,类内定义时不用inline即内联。
成员函数可以调用本类数据成员,无论公有或私有。
对象调用公有成员函数叫做发一个消息。
构造函数可以重载,带缺省参数时,要特别注意避免二义性。
构造函数一般都是公有函数。只有私有构造函数的类不能定义对象。
只有本类对象或本类成员函数才能调用成员函数。
6. This 指针
成员函数必须由对象调用,调用成员函数的对象可以看作一个隐含的参数,这是一个指针参数,用this表示。this 指针指向调用成员函数的对象。
例 Circle::CircleArea( )
{return 3.1416*radius*radius;}
//其中 radius 实际意义是this→radius .
Circle a(3.4);
cout <<a.CircleArea( );//this指针指向a
counter::increament( )
{if(value<65535)value++;}
//隐含参数this指针, this->value
counter c;
c.increament( );
//实际参数是c, this 指向c
7. 构造函数
与类名同名的成员函数叫构造函数,构造函数没有返回类型。构造函数的作用是自动为对象初始化。对象不能调用构造函数。
如果一个类中没有构造函数,系统会自动生成一个无参构造函数。如果一个类中有有参构造函数,系统就不再自动生成无参构造函数,这时,用类定义对象数组或对象指针都可能出错。
一个类中如果没有构造函数,系统会自动生成 一个无参构造函数,使所有的数据成员都置0。 一个类中如果有有参构造函数,系统就不再生 成无参构造函数。
例如 RecCirle类中,就没有无参构造函数。 这时要小心,下面一个语句会出错 RecCircle d; //出错 无法初始化 RecCircle s[3]; //出错 无法初始化
正确的定义形式是 RecCircle d(2.0, 3.5, 4);
8. 拷贝构造函数
构造函数的参数不能是本类对象,但可以是本类对象的引用,
这样的构造函数叫拷贝构造函数。
class Circle
{ float radius;
public:
Circle(float r=0):radius(r){}//构造函数
Circle(Circle & c){radius=c.radius;}
// 拷贝构造函数
float GetRadius( );
float CircleCircum( );
float CircleArea( );
};
拷贝构造函数的作用:
1) 用已有对象定义新的对象。
Circle a(2);
Circle b(a);
第二个语句就是利用拷贝构造函数定义赋数对象b, b的半径等于a的半径。
2) 本类对象作函数的参数时,要用拷贝构造函数传值。
3) 一个函数的返回值是本类对象时,要用拷贝构造函数赋值。
Circle Fun(Circle t)
{ return Circl(2*t.radius);}
如果类中没有拷贝构造函数系统会自动生成一个。
如果类中有指针成员,就必须专门定义拷贝构造函数,否则可能出错。
例 class A
{ int *p;
pubic:
A( ){p= new int(0);}
A(A&s){p=new int(*s.p);
};
9. 析构函数
以~开头与类名同名的成员函数称为析构函数。析构函数无参无返回值。
例 class A
{....
~A( );
....};
析构函数的作用: 当本类的一个对象用完后,系统自动调用析构函数,撤销内存。
这种情况常在一个函数中发生,一个对象在函数中作局部变元,函数用毕后,局部变元失效,析构函数就会自动起作用。
类中没有析构函数时系统会自动生成一个析构函数。
当类中含有指针对象时,应当定义一个析构函数,以免指针指向的内存挂起失。
class A
{ int *p;
public:
A( ){p=new int;}
....
~A( ){delete p;}
....};
注意 类外对象指针用 new 分配的内存,不会调用析构函数,而要用delete释放。
例 坐标点point类
class Point
{ public:
Point(int,int); //构造函数
Point(Point &);//拷贝构造函数
//~Point( ); 析构函数
int get_x( ); //取横坐标
int get_y( ); //取纵坐标
Point operator+(Point&); //重载+
Point operator *(int); //重载*
Point operator-( ); //一元函数-重载
Point& operator=(const Point&); //赋值函数
private: //私有数据
int x, y;
friend istream& operator>>(istream&, Point&);
//友元 输入函数重载>>
friend ostream& operator<<(ostream&,Point&);
//友元 输出函数重载<<
};
Point::Point(int a, int b)
{x=a; y=b;}
Point::Point(Point& p)
{x=p.get_x( ); y=p.get_y( );}
int Point::get_x( )
{return x;}
int Point::get_y( )
{return y;}
Point Point::operator+(Point &p)
{x=x+p.x; y=y+p.y; return*this;}
Point Point::operator *(int n)
{x=n*x; y=n*y; return*this;}
Point Point::operator-( )
{x=-x; y=-y; return *this;}
Point& Point::operator=(const Point& p)
{ x=p.x; y=p.y; return *this;}
istream& operator>>(istream& istr, Point& p)
{ istr>>p.x>>p.y; return istr; }
ostream& operator<<(ostream& ostr, Point& p)
{ ostr<<“(”<<p.x<<“,”<<p.y<<“)”<<endl;
return ostr; }
11. 运算符(操作符)重载
除了少数几个操作符,如 “,” ,“::” ,“?:” ,“{ }”之外,其余都可以重载。
二元运算在成员函数看来,只有一个参数,另一个是this指针。
例 Point Point::operator +(Point & c);
二元运算+在复数类中重载,变成只有一个参数。
Point a1(1,2) , a2(2,-1);
a1=a1+a2;
表达式a1=a1+a2中对象a1调用运算+,实
际参数为a2,返回值还是 Point类型,
还可以再调用运算符+,因此表达式
a1+a2+a1有意义。
12. 赋值函数重载
在class Point 中重载赋值函数
class Point
{ ....
Point& operator=(const Point& c)
{ x=c.x; y=c.y; return *this;}
......
};
赋值函数的作用是把一个对象的所有内容,赋予另一个对象.
c1=c2; c1=c1+c2;
类中没有赋值函数时系统会自动生成一个赋值函数。当类中含有指针对象时,应当定义一个赋值函数,以保证值把内容赋值,而不是把地址赋值造成析构函数调用时出错。
例 class A
{ int *p;
public:
.....
A& operator=(A& a)
{ if (this=&a) return *this;
else *p=*a.p;return *this;}
.....
};
13. 一元运算重载
一元运算作成员函数重载时变成零元函数。
Point Point :: operator -( )
{x=-x;y=-y;return return *this;}
调用写成 -c1 或 c1=-c2;
10. 友元
友元有权访问类内所有成员,不论公有,保护,还是私有成员。
友元没有this指针,必要时可以用类对象的引用作参数。
友元可以是一个类,这时友元类中所有成员函数都是友元。
友元不传递,不对称,不继承。
友元没有this指针,比成员函数多一个参数。
istream& operator>>(istream& istr, Point& p)
{ istr>>p.x>>p.y; return istr; }
ostream& operator<<(ostream& ostr, Point& p)
{ ostr<<“(”<<p.x<<“,”<<p.y<<“)”<<endl;
return ostr; }
友元不是类的成员,不用类名域 Point::operator
函数在类内申明类外定义 例 日期类保存于“date.h”中
class date
{ int month, day, year; //私有数据
public:
date(int, int, int); //有参构造函数
void next( );
void print( );
}today;
inline date::date(int a, int b, int c)
{ month=a; day=b; year=c;}
void date:: print( )
{ cout<<month<<“ /”<<day;
cout<<“ /”<<year<<endl;}
void date::next( )
{ switch month
case 1: case3: case 5: case 7: case 8: case 10:
{ if(day<31)day++;
else {month++;day=1;}}break;
case 4: case 6: case 9: case 11:
{ if(day<30)day++;
else {month++;day=1;}}break;
case 12:
{ if(day<31)day++;
else {year++;month=1;day=1;}}break;
case 2:
if((year%4==0)&&year%400!=0)
| |(year%400= =0))
{ if(day<29)day++;
else {month++;day=1;}}
else{ if(day<28)day++;
else {month++;day=1;}}
}
例 date 类测试程序
#include “ iostream.h”
#include “ date.h”
void main( )
{ date today(2,13,2001);//定义对象
date myBirthday(6,24,1983);//定义对象
today.next( );//对象调用操作
today.print( );
myBirthday.print( );
}
测试结果
2/14/2001
6/24/1983
本文详细介绍了C++中类的定义与使用,包括构造函数、成员函数、对象指针等核心概念,并提供了丰富的示例代码,帮助读者深入理解面向对象编程的基础。
614

被折叠的 条评论
为什么被折叠?



