类(Classes)
类(class)是一种将数据和函数组织在同一个结构里的逻辑方法。定义类的关键字为
class ,其功能与 C 语言中的 struct 类似,不同之处是 class 可以包含函数,而不像
struct 只能包含数据元素。(请注意这里是相对于C语言来说的,C++中struct 和 class关
键字类似,仅在于默认的访问权限不同)
类定义的形式是:
class class_name {
permission_label_1:
member1;
permission_label_2:
member2;
...
} object_name;
其中 class_name 是类的名称 (用户自定义的类型) ,而可选项 object_name 是一个或
几个对象(object)标识。Class 的声明体中包含成员 members,成员可以是数据或函数
定义,同时也可以包括允许范围标志 permission labels,范围标志可以是以下三个关键
字中任意一个:private:, public: 或 protected:。它们分别代表以下含义:
•private :class 的 private 成员,只有同一个 class 的其他成员或该 class 的
“friend” class 可以访问这些成员。
•protected :class 的 protected 成员,只有同一个 cl ass 的其他成员,或该 class
的“friend” class,或该 class 的子类(derived classes) 可以访问这些成员。
•public :class 的 public 成员,任何可以看到这个 class 的地方都可以访问这
些成员。
如果我们在定义一个 class 成员的时候没有声明其允许范围,这些成员将被默认为
private 范围。
例如:
class CRectangle {
int x, y;
public:
void set_values (int,int);
int area (void);
} rect;
上面例子定义了一个 class CRectangle 和该 class 类型的对象变量 rect 。这个 class
有 4 个成员:两个整型变量 (x 和 y) ,在 private 部分 (因为 private 是默认的允许
范围);以及两个函数, 在 public 部分:set_values() 和 area(),这里只包含了函
数的原型(prototype)。
注意 class 名称与对象(object)名称的不同:在上面的例子中,CRectangle 是 class
名称 (即用户定义的类型名称),而 rect 是一个 CRectangle 类型的对象名称。它们的区
别就像下面例子中类型名 int 和 变量名 a 的区别一样:
Int a;
int 是 class 名称 (类型名) ,而 a 是对象名 object name (变量)。
在程序中,我们可以通过使用对象名后面加一点再加成员名称(同使用 C structs 一样),
来引用对象 rect 的任何 public 成员,就像它们只是一般的函数或变量。例如:
rect.set_value (3,4);
myarea = rect.area();
但我们不能够引用 x 或 y ,因为它们是该 class 的 private 成员,它们只能够在该
class 的其它成员中被引用。晕了吗?下面是关于 class CRectangle 的一个复杂的例子:
// classes xample
#include
class CRectangle {
int x, y;
public:
void set_values (int,int);
int area (void) {return (x*y);}
};
void CRectangle::set_values (int a, int
b) {
x = a;
y = b;
}
int main () {
CRectangle rect;
rect.set_values (3,4);
cout << "area: " << rect.area();
}
area: 12
上面代码中新的东西是在定义函数 set_values().使用的范围操作符(双冒号:: )。它是
用来在一个 class 之外定义该 class 的成员。注意,我们在 CRectangle class 内部已经
定义了函数 area() 的具体操作,因为这个函数非常简单。而对函数 set_values() ,在
class 内部只是定义了它的原型 prototype,而其实现是在 class 之外定义的。这种在
class 之外定义其成员的情况必须使用范围操作符::。
范围操作符 (: 声明了被定义的成员所属的 class 名称,并赋予被定义成员适当的范
围属性,这些范围属性与在 class 内部定义成员的属性是一样的。例如,在上面的例子
中,我们在函数 set_values() 中引用了 private 变量 x 和 y,这些变量只有在 class
内部和它的成员中才是可见的。
在 class 内部直接定义完整的函数,和只定义函数的原型而把具体实现放在 class 外部
的唯一区别在于,在第一种情况中,编译器(compiler) 会自动将函数作为 inline 考虑,
而在第二种情况下,函数只是一般的 class 成员函数。
我们把 x 和 y 定义为 private 成员 (记住,如果没有特殊声明,所有 class 的成员均
默认为 private ),原因是我们已经定义了一个设置这些变量值的函数
(set_values()) ,这样一来,在程序的其它地方就没有办法直接访问它们。也许在一个
这样简单的例子中,你无法看到这样保护两个变量有什么意义,但在比较复杂的程序中,
这是非常重要的,因为它使得变量不会被意外修改 (这里意外指的是从 object 的角度
来讲的意外)。
使用 class 的一个更大的好处是我们可以用它来定义多个不同对象(object)。例如,
接着上面 class CRectangle 的例子,除了对象 rect 之外,我们还可以定义对象 rectb :
// class xample
#include
class CRectangle {
int x, y;
public:
void set_values (int,int);
int area (void) {return (x*y);}
};
void CRectangle::set_values (int a, int
b) {
x = a;
y = b;
}
int main () {
CRectangle rect, rectb;
rect.set_values (3,4);
rectb.set_values (5,6);
cout << "rect area: " << rect.area()
<< endl;
cout << "rectb area: " << rectb.area()
<< endl;
}
rect area: 12
rectb area: 30
注意: 调用函数 rect.area() 与调用 rectb.area()所得到的结果是不一样的。这是因为
每一个 class CRectangle 的对象都拥有它自己的变量 x 和 y,以及它自己的函数
set_value() 和 area()。
这是基于对象( object) 和 面向对象编程 (object-oriented programming)的概念的。
这个概念中,数据和函数是对象(object)的属性(properties),而不是像以前在结构化
编程 (structured programming) 中所认为的对象(object)是函数参数。在本节及后面
的小节中,我们将讨论面向对象编程的好处。
在这个具体的例子中,我们讨论的 class (object 的类型)是 CRectangle,有两个实例
(instance),或称对象(object):rect 和 rectb,每一个有它自己的成员变量和成员函
数。
构造函数和析构函数 (Constructors and destructors)
对象(object)在生成过程中通常需要初始化变量或分配动态内存,以便我们能够操作,
或防止在执行过程中返回意外结果。例如,在前面的例子中,如果我们在调用函数
set_values( ) 之前就调用了函数 area(),将会产生什么样的结果呢?可能会是一个不
确定的值,因为成员 x 和 y 还没有被赋于任何值。
为了避免这种情况发生,一个 class 可以包含一个特殊的函数:构造函数 constructor,
它可以通过声明一个与 class 同名的函数来定义。当且仅当要生成一个 class 的新的实
例 (instance)的时候,也就是当且仅当声明一个新的对象,或给该 class 的一个对象分
配内存的时候,这个构造函数将自动被调用。下面,我们将实现包含一个构造函数的
CRectangle :
// class xample
#include
class CRectangle {
int width, height;
public:
CRectangle (int,int);
int area (void) {return
(width*height);}
};
CRectangle::CRectangle (int a, int b) { //构造函数没有返回值
width = a;
height = b;
}
int main () {
CRectangle rect (3,4);
CRectangle rectb (5,6);
cout << "rect area: " << rect.area()
<< endl;
cout << "rectb area: " << rectb.area()
<< endl;
}
rect area: 12
rectb area: 30
正如你所看到的,这个例子的输出结果与前面一个没有区别。在这个例子中,我们只
是把函数set_values换成了class的构造函数constructor。注意这里参数是如何在class
实例 (instance)生成的时候传递给构造函数的:
CRectangle rect (3,4);
CRectangle rectb (5,6);
同时你可以看到,构造函数的原型和实现中都没有返回值(return value),也没有 void
类型声明。构造函数必须这样写。一个构造函数永远没有返回值,也不用声明 void,就
像我们在前面的例子中看到的。
析构函数 Destructor 完成相反的功能。它在 objects 被从内存中释放的时候被自动
调用。释放可能是因为它存在的范围已经结束了(例如,如果 object 被定义为一个函数
内的本地(local)对象变量,而该函数结束了);或者是因为它是一个动态分配的对
象,
而被使用操作符 delete 释放了。
析构函数必须与 class 同名,加水波号 tilde (~) 前缀,必须无返回值。
析构函数特别适用于当一个对象被动态分别内存空间,而在对象被销毁的时我们希望释
放它所占用的空间的时候。例如:
// example on constructors and
destructors
#include
class CRectangle {
int *width, *height;
public:
CRectangle (int,int);
~CRectangle ();
int area (void) {return (*width *
*height);}
};
CRectangle::CRectangle (int a, int b) {
width = new int;
height = new int;
*width = a;
*height = b;
}
CRectangle::~CRectangle () {
delete width;
delete height;
}
int main () {
CRectangle rect (3,4), rectb (5,6);
cout << "rect area: " << rect.area()
<< endl;
cout << "rectb area: " << rectb.area()
<< endl;
return 0;
}
rect area: 12
rectb area: 30
构造函数重载(Overloading Constructors)
像其它函数一样,一个构造函数也可以被多次重载(overload)为同样名字的函数,但有
不同的参数类型和个数。记住,编译器会调用与在调用时刻要求的参数类型和个数一样
的那个函数(Section 2.3, Functions-II)。在这里则是调用与类对象被声明时一样的那
个构造函数。
用户1711475 2015-4-15 10:33
用户1739951 2015-4-1 17:27
用户1221358 2015-4-1 08:07
用户403664 2014-2-17 08:51
用户579229 2014-2-15 11:10
用户377235 2014-2-15 11:06
用户377235 2014-2-15 11:05
这是第二次评论,测试看看游客能否评论,上一次评论如下: 楼主这篇文章没有看完,开头就太幼稚了。 第一处错误: class和struct的区别大错而特错了:他们的区别绝对不是包含函数的问题,而是,在默认情况下,struct的member是公有的public属性;而默认情况下,class的members是私有的private属性。 其次,struct理所当然的可以包含函数。我可以绝对有把握的说楼主根本就没有研究过linux内核。各种大量的file_operations结构体,都是一个个的函数指针,从某种意义上来讲,和class定义函数方法是一模一样的,并且,struct利用定义函数指针的方法来隐藏方法。 第二处明显错误: private的用法和理解明显的错误,根本就不是自己class的成员来访问,因为楼主根本就不理解class和object的含义。一个定义的类用constructor初始化这个类的一个object以后,这个object通过自己的成员函数来访问自己的私有成员。 这个和楼主的理解大相径庭。还有,请问一个类的friend函数能不能访问这个类的私有成员,还是只有这个类的friend class能访问这个类的私有成员。继承类能不能访问这个类的私有成员? 漏洞百出,漏洞百出,漏洞百出。 不忍直视。后面就不看了。 希望看到这篇博文的学员不要被此文章误导,造成理解上的巨大偏差,赶紧跳过。 谢谢。
用户377235 2014-2-15 08:58