|
|
|
类是数据以及用于操纵该数据的方法(函数)的集合,是逻辑上相关函数与数据的封装。它是对所要处理问题的抽象描述,它把数据(事物的属性)和函数(事物的行为/操作)封装为一个整体。
|
|
|
|
|
|
其中,private、 public、 protected称为访问权限控制关键字,其作用是限制"可见性"。在类的定义中,以上3种关键字出现的次数和先后次序都没有限制,默认被认为是private。这3种关键字对应的访问可见性如下。
|
|
|
.private:私有成员,只能在成员函数内访问。
|
|
|
|
.protected:保护成员,只能由对象内部或其派生类对象访问。
|
|
|
面向对象的思想是对对象的属性(成员变量)进行操作,应该通过对象的方法(成员函数)来进行,对象的方法是对象和外部的接口。将类的成员变量声明为private,能保证对该成员的操作都是通过类的方法来进行的。这样可以避免出错(如对成员变量不恰当地赋值),也便于修改程序。在修改类的定义时,只要修改类的成员函数就可以了,不需要修改使用该类成员的代码。如果某些成员函数只被其他成员函数调用,不作为对象的界面,那么也可以将它声明为private。
|
|
|
|
|
其中,运算符"::"称为作用域解析运算符,它指出该函数是属于哪一个类的成员函数。当然也可以在类的定义中直接定义函数。
|
|
|
|
|
|
(1)第一种是直接定义类的对象。如CGoodsCar这个定义创建了CGoods类的一个对象Car,同时为它分配了属于它自己的存储块,用来存放数据和对这些数据实施操作的成员函数(代码)。与变量定义一样,一个对象只在定义它的域中有效。第一种方法通过"对象名.成员名"方式访问对象成员。
|
|
|
(2)第二种是采用动态创建类的对象的方法,当然变量也同样可动态创建。所谓动态,是指在程序运行时建立对象。而第一种方法是在编译时(程序运行前)建立。第二种方法通过对象指针访问对象成员。
|
|
|
|
|
|
(1)是成员函数的一种,名字与类名相同,可以有参数,不能有返回值(void也不行)。
|
|
|
(2)其作用是对对象进行初始化,如给成员变量赋初值。
|
|
|
(3)如果定义类时没写构造函数,则编译器生成一个默认的无参数的构造函数。默认构造函数无参数,什么也不做。默认的构造函数也可以由程序员自己来编写,只要构造函数是无参的或者只要各参数均有默认值,C++编译器都认为是默认的构造函数,并且默认的构造函数只能有一个。
|
|
|
(4)如果定义了构造函数,则编译器不生成默认的无参数的构造函数。
|
|
|
|
(6)一个类可以有多个构造函数,它们的参数个数或类型不同,构成函数重载。
|
|
|
构造函数一般声明为public,当然有时为了特殊需要也可定义为private。
|
|
|
|
同一个类的对象在内存中有完全相同的结构,如果作为一个整体进行复制是完全可行的。这个复制过程只需要复制数据成员,而函数成员是共用的(只有一份副本)。
|
|
|
在建立对象时可用同一类的另一个对象来初始化该对象,这时所用的构造函数称为复制初始化构造函数(CopyConstructor)。形如X::X(X&),只有一个参数——同类(Class)的对象,采用的是引用的方式。不允许有形如X::X(X)的构造函数,如果把一个真实的类对象作为参数传递到复制构造函数,会引起无穷递归。如果没有定义,那么编译器生成默认复制构造函数。如果定义了自己的复制构造函数,则默认的复制构造函数不存在。
|
|
|
|
|
|
(2)如果某函数有一个形参是类A的对象,那么该函数被调用时,类A的复制构造函数将被调用。
|
|
|
|
(3)如果函数的返回值是类A的对象,则函数返回时,A的复制构造函数被调用。理由也是要建立一个临时对象,再返回调用者。
|
|
|
|
为什么不直接用要返回的局部对象呢?因为局部对象在离开建立它的函数时就消亡了,不可能在返回调用函数后继续生存。所以编译系统会在调用函数的表达式中创建一个无名临时对象,该临时对象的生存周期只在函数调用处的表达式中。所谓return对象,实际上是调用复制构造函数把该对象的值复制到临时对象。
|
|
|
|
当一个对象定义时,C++自动调用构造函数建立该对象并进行初始化,那么当一个对象的生命周期结束时,C++也会自动调用一个函数注销该对象并进行善后工作,这个特殊的成员函数即析构函数(Destructor)。
|
|
|
(1)析构函数名也与类名相同,但在前面加上字符"~",如~CGoods()。
|
|
|
(2)析构函数无函数返回类型,在这方面与构造函数是一样的,但析构函数不带任何参数。
|
|
|
(3)一个类有一个也只有一个析构函数,这与构造函数不同。析构函数可以缺省。
|
|
|
|
|
对于不同作用域的对象类型,构造函数和析构函数的调用如下。
|
|
|
(1)对于全局定义的对象,当程序进入入口函数main之前对象就已经定义,这时要调用构造函数。整个程序结束时,调用析构函数。
|
|
|
(2)对于局部定义的对象,每当程序控制流到达该对象定义处时,调用构造函数。当程序控制流走出该局部域时,调用析构函数。
|
|
|
(3)对于静态局部定义的对象,在程序控制流首次到达该对象定义处时,调用构造函数。当整个程序结束时,调用析构函数。
|
|
|
|
有成员对象的类称为封闭(Enclosing)类。对成员对象初始化,必须调用该成员对象的构造函数来实现。先调用所有对象成员的构造函数,然后才调用封闭类的构造函数。对象成员的构造函数调用次序和对象成员在类中的说明次序一致,与它们在成员初始化列表中出现的次序无关。当封闭类的对象消亡时,先调用封闭类的析构函数,然后再调用成员对象的析构函数,次序和构造函数的调用次序相反。
|
|
|
|
|