C++类与对象
为了提高软件的复用率与可维护性,现代程序设计方法学中指出,一个软件系统的框架应该建立在数据之上,而不是操作之上。即在构成软件系统的每个相对独立的模块上定义一组数据和施于这些数据之上的一组操作,并在模块内部给出这些数据的表示与操作细节,而在模块外部使用的只是抽象的数据与抽象的操作。
类是一种抽象数据类型ADT(abstract data type),它是一种用户自己定义的数据类型。它实现了数据抽象和封装的数据类型,它封装了复杂数据与操纵复杂数据的程序代码。
(一)类的定义与声明
类的一般形式为:
class{
成员列表
};
成员列表是类成员的集合,由具体应用而定;大括号是成员列表的边界符,与成员列表一起称为类体。
1)类的数据成员
除了在类中声明一般的数据成员外,还可以在类中定义自己的局部数据类型,并且使用类型别名来简化。
class ADT{
struct Point{int x,y;}; //定义结构体
union UData{Point p; long color;}; //定义共用体
enum COLOR{RED,GREEN,BLUE}; //定义枚举类型
class Nested{ //嵌套类定义
... //成员函数
Point start; //数据成员
UData end;
COLORS color;
};
typedef Point* LPPOINT; //声明Point的类型别名
... //ADT的成员函数
... //ADT的数据成员
};
在类中定义或声明的数据类型的作用域是类内部,因此它们不能在类外部使用。
2)类的成员函数
成员函数必须要在成员列表类中声明,而成员函数的定义即可以在类的内部也可以在类的外部。一般来说在类的内部对成员函数做声明,在类的外部定义成员函数,是一种比较好的编程习惯。这样使得类体的长度变短,类结构变得清晰,而且有助于类的接口与实现分离。
class Data{
public:
void set (int d); //成员函数原型声明
int get(){ //成员函数定义
return data;
}
private:
int data; //数据成员
};
void Data::set(int data) //成员函数的外部定义,使用::类作用域限定符。
{
data=d;
}
void set(int d) //全局普通函数
{}
如果作用域限定符前面不是类名,比如我们在视觉领域常见到的cv::f(),这时::指的是命名空间域限定符。
注意:为了节约空间,C++中每个类的对象所占用的存储空间只是该对象的数据成员所占用的存储空间,不包括成员函数存储空间。成员函数代码只有公共的一个,调用不同对象的成员函数时都是执行同一段函数空间。
(二)成员访问控制
类的所有成员都有访问控制属性,由下面三种访问标号说明:public,private,protected,访问控制属性用于控制类成员在程序中的可访问性。
公有成员允许外部类用户直接通过对象访问,也允许类内部的成员函数直接访问。私有成员只有类成员函数才能访问,它实现了私有成员的隐蔽。保护成员在不考虑继承的情况下,与私有成员性质一致,但是保护成员可以被派生类的类成员函数访问。
class{
public:
...
protected:
...
private:
...
};
注意,如果有成员没有被生声明上述的访问控制属性,则默认其为私有的。
(三)对象的定义与使用
1)定义对象的三种方法:
a)先定义类类型,然后定义类对象。比如说之前已经定义了Point类,下面定义Point类的对象:
Point a,b; //C++特色定义对象
class Point x,y; //兼容C语言特色定义对象
b)定义类类型的同时定义对象。
class Data{ //类名
...
}one, two; //对象列表
c)直接定义对象。
class { //无类名类体
...
}one,two;
其中第一种方法最灵活最普遍。
2)对象的动态建立与释放
前面介绍的静态存储对象占用空间的分配与释放时间点是固定的。例如,在某函数中定义一个对象,进入函数运行时,为对象分配存储空间;函数结束运行时,释放对象占用的空间。
为了提高存储空间的利用率,可以使用new运算符动态分配对象空间,delete运算符释放对象空间:
类名* 对象指针变量;
对象指针变量=new 类名;
Point* p; //定义指向Point对象的指针变量
p=new Point; //动态分配Point对象
当不需要使用new建立的动态对象时,必须使用delete运算撤销,例如:
delete p; //撤销p所指的对象
注意:new建立的对象不会自动被撤销,即使程序结束也是如此,必须人为使用delete撤销。
3)对象成员的引用
访问对象中的成员有以下三种方法:
a)通过对象名与对象成员引用运算(.)访问对象成员。
Data A,B;
A.data=10;
A.add(5);
b)通过指向对象的指针和指针成员引用运算(->)访问对象成员。
Data A,*p,*p1;
p=&A;
p->data=10;
p->add(5)
p1=new Data;
p1->data=10;
delete p;
c)通过对象的引用变量和对象成员引用运算(.)访问对象成员。
Data A,&r=A; //定义对象的引用变量
r.data=100;
r.fun(1,2,3);