类
面向对象的程序设计方法,能够较好结构化设计方法中遇到的问题。
面向对象的程序 = 类 + 类 + …+ 类
1、面向对象的程序设计方法:
将某类客观事物共同特点(属性)归纳出来,形成一个数据结构(可以用多个变量描述事物的属性);
将这类事物所能进行的行为也归纳出来,形成一个个函数,这些函数可以用来操作数据结构(这一步叫“抽象”)。
然后,通过某种语法形式,将数据结构和操作该数据结构的函数“捆绑”在一起,形成一个“类”,从而使得数据结构和操作该数据结构的算法呈现出显而易见的紧密关系,这就是“封装”。
面向对象的程序设计具有:
-“抽象”
-“封装”
-“继承”
-“多态”
四个基本特点。
面向对象的程序设计模式:
2、举例:
将长、宽变量和设置长,宽,求面积,以及求周长的三个函数“封装”在一起,就能形成一个“矩形类”。
长、宽变量成为该“矩形类”的“成员变量”,三个函数成为该类的“成员函数” 。 成员变量和成员函数统称为类的成员。
class CRectangle {
public:
int w, h;
int Area() {
return w * h;
}
int Perimeter(){
return 2 * ( w + h);
}
void Init( int w_,int h_ ) {
w = w_; h = h_;
}
}; //必须有分号
int main( )
{
int w,h;
CRectangle r; //r是一个对象
cin >> w >> h;
r.Init( w,h);
cout << r.Area() << endl << r.Perimeter();
return 0;
}
通过类,可以定义变量。类定义出来的变量,也称为类的实例,就是我们所说的“对象” 。
类的名字就是用户自定义的类型的名字。可以象使用基本类型那样来使用它。
和结构变量一样,对象所占用的内存空间的大小,等于所有成员变量的大小之和。
每个对象各有自己的存储空间。一个对象的某个成员变量被改变了,不会影响到另一个对象。
和结构变量一样,对象之间可以用 “=”进行赋值,但是不能用 “==”,“!=”,“>”,“<”“>=”“<=”进行比较,除非这些运算符经过了“重载”。
3、用法
[1] 用法1:对象名.成员名
CRectangle r1,r2;
r1.w = 5;
r2.Init(5,4);
Init函数作用在 r2 上,即Init函数执行期间访问的 w 和 h是属于 r2 这个对象的, 执行r2.Init 不会影响到 r1。
[2 ] 用法2:指针->成员名
CRectangle r1,r2;
CRectangle * p1 = & r1;
CRectangle * p2 = & r2;
p1->w = 5;
p2->Init(5,4); //Init作用在p2指向的对象上
[ 3] 用法3:引用名.成员名
CRectangle r2;
CRectangle & rr = r2;
rr.w = 5;
rr.Init(5,4); //rr的值变了,r2的值也变
void PrintRectangle(CRectangle & r)
{
cout << r.Area() << ","<< r.Perimeter();
}
CRectangle r3;
r3.Init(5,4);
PrintRectangle(r3);
4、类成员的可访问范围
在类的定义中,用下列访问范围关键字来说明类成员可被访问的范围:
–private: 私有成员,只能在成员函数内访问
–public : 公有成员,可以在任何地方访问
–protected: 保护成员。
如过某个成员前面没有上述关键字,则缺省地被认为是私有成员。
类成员的可访问范围
class Man {
int nAge; //私有成员
char szName[20]; // 私有成员
public:
void SetName(char * szName){
strcpy( Man::szName,szName);
}
};
在类的成员函数内部,能够访问:
–当前对象的全部属性、函数;
–同类其它对象的全部属性、函数。
在类的成员函数以外的地方,只能够访问该类对象的公有成员。
class CEmployee {
private:
char szName[30]; //名字
public :
int salary; //工资
void setName(char * name);
void getName(char * name);
void averageSalary(CEmployee e1,CEmployee e2);
};
void CEmployee::setName( char * name) {
strcpy( szName, name); //ok
}
void CEmployee::getName( char * name) {
strcpy( name,szName); //ok
}
void CEmployee::averageSalary(CEmployee e1, CEmployee e2){
cout << e1.szName; //ok,访问同类其他对象私有成员
salary = (e1.salary + e2.salary )/2;
}
int main()
{
CEmployee e;
strcpy(e.szName,"Tom1234567889"); //编译错,不能访问私有成员
e.setName( "Tom"); // ok
e.salary = 5000; //ok
return 0;
}
5、构造函数 (constructor)
成员函数的一种
名字与类名相同,可以有参数,不能有返回值(void也不行)
作用是对对象进行初始化,如给成员变量赋初值
如果定义类时没写构造函数,则编译器生成一个默认的无参数的构造函数
默认构造函数无参数,不做任何操作
如果定义了构造函数,则编译器不生成默认的无参数的构造函数
对象生成时构造函数自动被调用。对象一旦生成,就再也不能在其上执行构造函数
一个类可以有多个构造函数
class Complex {
private :
double real, imag;
public:
void Set( double r, double i);
}; //编译器自动生成默认构造函数
Complex c1; //默认构造函数被调用
Complex * pc = new Complex; //默认构造函数被调用
6、复制构造函数 copy constructor
只有一个参数,即对同类对象的引用。
形如 X::X( X& )或X::X(const X &), 二者选一 后者能以常量对象作为参数
如果没有定义复制构造函数,那么编译器生成默认复制构造函数。默认的复制构造函数完成复制功能
class Complex {
private :
double real,imag;
};
Complex c1; //调用缺省无参构造函数
Complex c2(c1);//调用缺省的复制构造函数,将 c2 初始化成和c1一样
如果定义的自己的复制构造函数, 则默认的复制构造函数不存在。
class Complex {
public :
double real,imag;
Complex(){ }
Complex( const Complex & c ) {
real = c.real;
imag = c.imag;
cout << “Copy Constructor called”;
}
};
Complex c1;
Complex c2(c1);
复制构造函数起作用的三种情况
当用一个对象去初始化同类的另一个对象时。
Complex c2(c1);
Complex c2 = c1; //初始化语句,非赋值语句
如果某函数有一个参数是类 A 的对象, 那么该函数被调用时,类A的复制构造函数将被调用。
void Func(A a1){ }
int main()
{
A a2;
Func(a2);
return 0;
}
如果函数的返回值是类A的对象时,则函数返回时, A的复制构造函数被调用:
class A
{
public: int v;
A(int n) { v = n; };
A( const A & a) {
v = a.v;
cout << "Copy constructor called" <<endl;
}
};