[总结]C++真是博大精深(二)

来源:互联网 发布:智多星造价软件多少钱 编辑:程序博客网 时间:2024/05/23 23:51

类与对象

(最终解释权归原作者所有,侵权必究)

1、面向对象的编程,就是利用抽象、封装、继承和多态机制来完成程序的组织和编写。

2、C++语言中的类,既可以具有各种属性(数据成员),也可以具有对这些属性进行操作的方法(成员函数)。C++语言中类声明的基本形式如下:class 类名{ private:私有数据成员和私有成员函数  public:公有数据成员和公有成员函数  protected:保护数据成员和保护成员函数};

3、class是声明类的关键字,类名是要声明的类的名称(标识符),一对花括号括起来的部分称为类体,类体中包含数据成员和成员函数的声明。在类声明的最后,用分号标识类声明的结束。在类中,数据成员又称为成员变量,成员函数又称为方法。

4、关键字private、public和protected称为访问权限控制符。其中,private限定数据成员和成员函数是私有的,这类成员通常只能被本类的成员函数访问或调用;public限定数据成员和成员函数是公开的,这类成员对外是开放的,既可以被本类的成员函数访问或调用,又可以在外部通过类对象等方式直接进行访问或调用;protected限定数据成员和成员函数时保护类型的,通常只能被本类的成员函数和其派生类的成员函数进行访问和调用。private、public和protected这三部分的顺序是可以自由安排的。当关键字private紧接着类的第一个花括号时,可以省略该关键字,即类成员默认是私有的。

5、类的成员函数属于类的成员,它可以访问或调用本类的任何数据成员和成员函数。成员函数可以被限定为私有的(private)、公有的(public)或受保护的(protected)。对于私有成员函数,通常只能被本类的其他成员函数所调用;对于公有成员函数,可以作为类对外的接口,被外部调用。

6、成员函数可以被定义为非内联成员函数,也可以被定义为内联成员函数。

  ⑴将成员函数定义为非内联成员函数

    当采用这种定义方式时,在类声明中只给出成员函数的原型,而在类声明的外面给出成员函数的完整定义。其定义的形式为:函数返回值类型类名::成员函数名(参数表){ 函数体 }。

    当在类声明的外面定义成员函数时,需要在函数名的前面加上类名和作用域运算符::,以标明该函数是属于该类的。成员函数的声明中可以只包括函数参数的类型,省略参数的名称。

  ⑵将成员函数定义为内联成员函数

    当成员函数被定义为内联成员函数后,可减少成员函数的调用开销,提高执行效率,但是这种做法增加了编译后的代码长度,因此只有很短的成员函数才考虑定义为内联成员函数。定义内联成员函数的两种方法:隐式定义和显式定义。

    ①内联成员函数的隐式定义

      直接将成员函数定义在类的内部。对于这种情况,C++编译器将这种函数作为内联函数进行处理。

    ②内联成员函数的显式定义

      为了使类结构清晰,可以将内联成员函数的定义放在类外。为了说明该函数是内联函数,要在函数定义前冠以关键字inline。

7、类是某类食物共同属性和共同行为的抽象,而对象则是类的某一个实例。类对象定义的形式为:类名对象名1,对象名2……;

⑴通过对象名和对象选择符”.”访问对象的成员,其形式为:对象名.数据成员名;或者对象名.成员函数名(实参表)。

  通常要将数据成员定义成私有的,是为了限制外界对数据成员的自由访问,避免对数据成员值的随意改动。通过定义私有数据成员和访问私有数据成员的公有成员函数,可以限定外界对数据成员的操作,从而保证数据的安全性,达到对数据进行封装的目的。

⑵通过指向对象的指针访问对象的成员。可以定义某个类类型的指针变量,使其指向该类的一个对象。在使用该指针时,可通过->操作符访问其指向对象的成员。

⑶通过对象的引用访问对象的成员。对象引用相当于是另一个对象的别名,因此可以通过对象引用访问对象的成员。

8、在C++中,结构体也具有类的基本功能,可以有各类数据成员和成员函数。其主要区别在于类的成员默认是私有的,而结构体默认是公有的。

9、构造函数:进行数据成员的初始化。

  ⑴在定义对象时,构造函数自动被调用,完成对象的内存空间分配及数据成员的初始化。

  ⑵构造函数的名称必须与类名相同。

  ⑶构造函数没有函数返回值,也不能指定函数返回值类型。

  ⑷在定义对象时,通过new运算符分配类对象的内存时,会自动调用构造函数。

  ⑸构造函数一般为公有成员,但是它不能被显式调用。

  ⑹不需要显式提供实际参数就能调用的构造函数称为默认构造函数,包括不带参数的构造函数和所有形参都有默认参数的构造函数。如果用户没有显式地在类中写出构造函数,那么系统会为该类自动生成一个不带参数的默认构造函数。该默认构造函数的形式为类名::类名(){ },参数表和函数体都是空的。

10、同普通函数一样,构造函数也可以被重载。利用重载的构造函数,可以采用多种方式完成类对象的初始化。

  ⑴如果用户没有显示地定义类的构造函数,系统会生成一个函数体为空的构造函数。一旦类中已经定义了一个构造函数,系统就不再提供默认构造函数。

  ⑵当使用默认构造函数创建对象时,应使用类名 对象名;但不能写成类名 对象名();因为系统会把其解释为一个函数声明。

11、对于带参数的构造函数,必须在定义对象时给构造函数传递实参。而在许多实际应用中,类对象可以取相同的初值,这时可以使用带默认参数的构造函数。注意:在类的构造函数声明中给出了默认参数后,不能在类外的函数定义处再次指定默认值。

12、析构函数在对象消亡时被自动调用,可用于内存清理工作或数据保存工作。如可以在析构函数中释放由new运算符分配的内存,在windows窗口被关闭时通过析构函数保存窗口的内容。

  ⑴析构函数的名称由类名和前面的波浪号~构成,即~类名

  ⑵析构函数没有参数,因此不能被重载。每个类只能有一个析构函数。

  ⑶析构函数没有函数返回值,也不能指定它的函数返回值类型。

  ⑷对象消亡时,系统会自动调用该对象的析构函数。如果一个对象是通过new运算符动态生成的,那么在通过delete运算符释放该对象时,会自动调用析构函数。

  ⑸每个类都必须有一个析构函数,如果没有显式地定义析构函数,编译系统会自动生成一个默认析构函数。默认析构函数的函数体是空的。该默认析构函数的功能是释放对象所占据的存储空间。

  ⑹先构造后析构,后构造先析构。

13、复制构造函数是一种特殊的构造函数,当创建一个新对象时,使用已经定义的对象去初始化这个新对象。复制构造函数的形式为:类名(const 类名 &引用对象名),复制构造函数参数是一个常引用对象。

  ⑴大多数情况下,不需要用户显式地定义复制构造函数,系统通过调用默认复制构造函数就能够完成新对象的初始化工作。默认的复制构造函数对对象的每一个数据成员执行成员复制操作。但是,某些情况下,默认的复制构造函数会带来指针悬挂问题。

  ⑵出现指针悬挂问题的根本原因在于默认的复制构造函数只完成了对象之间的地址复制(即使得两个对象的指针均指向了相同的内存空间),这种指针变量的浅层复制会造成指针悬挂问题。实际上,这两个对象的各个指针变量应该各自拥有分配给自己的不同内存空间。该深层复制是通过自定义的复制构造函数实现的。

  ⑶在以下3种情况下,会调用复制构造函数:

    ①当使用某类的一个已存在的对象去初始化该类的另一个对象时,如CStudent student2(student1)或CStudentstudent3 = student1;’

    ②当函数的形参是某类的对象时,在调用该函数时,实参对象向形参对象传递值,需要调用复制构造函数。

    ③如果函数的返回值是某类的对象,那么在函数调用时,会调用复制构造函数,以把返回至对象复制给另一个对象。

14、对象数组是指每一个数组元素都是对象的数组,对象指针是指存放对象地址的指针变量。定义一维对象数组的格式为:类名数组名[数组长度];声明对象指针的格式为:类名 *对象指针名。

15、当用const限定类的成员时,被限定的成员是称为常对象成员;当用const限定类对象时,被限定的对象称为常对象。

  ⑴常对象成员分为常成员函数和常数据成员两种。使用const限定的成员函数成为常成员函数,常成员函数不能修改对象数据成员的值,它通常用于获取对象的状态。在类中,使用const进行限定的数据成员称为常数据成员。常数据成员只能在构造函数中通过初始化表的方式进行初始化,任何成员函数都不能对常数据成员进行赋值。常数据成员一旦被初始化,其值不能改变。

  ⑵常对象在定义时就必须要初始化。常对象的数据成员值在对象的整个生命周期内不能被改变,为了对常对象进行保护,不允许常对象调用非常成员函数,只允许调用常成员函数。

  ⑶声明常成员函数:返回类型 函数名(参数表)const;

定义常成员函数:返回类型 函数名(参数表) const{  }

在声明和定义常成员函数时都要加上关键字const。

  ⑷常对象的说明:const 类名 对象名(参数表);或类名 const 对象名(参数表);

  ⑸构造函数初始化表用于完成数据成员的初始化。构造函数初始化表以一个冒号开始,然后是以逗号分隔的数据成员列表,每个数据成员后面跟一对圆括号,圆括号中是该数据成员的初始化式。如CTime::CTime(int h,int m,int s):m_hour(h),m_minute(m),m_second(s){ }。这里,初始化式可以是复杂的表达式。可以使用构造函数初始化表代替构造函数体内的赋值语句,完成数据成员的初始化。

  ⑹对于常数据成员,只能通过构造函数体内的赋值语句,完成数据成员的初始化,而不能在构造函数的函数体中通过赋值语句进行初始化。

  ⑺当数据成员是引用类型时,也只能通过使用构造函数初始化表的形式进行初始化。

16、C++编译系统中同一个类的各个对象的存储空间存放的是各自的数据成员,而成员函数代码存放在对象空间之外,由该类的所有对象合用。当对象调用某一成员函数时,该成员函数通过this指针判断哪个对象调用它。

  ⑴C++为类的每个成员函数都提供了一个隐含的名字为this的指针参数:类名 &const this。在成员函数中,隐含了对this指针的使用。this指针的值随对象的不同会发生改变。

  ⑵this指针的用途:帮助成员函数区分对象;用于表示对象本身;当需要在类的非静态成员函数中返回类对象本身时,可以使用return *this;当成员函数的形参名与数据成员的变量名相同时,如果需要进行二者之间的赋值操作,可以通过this指针进行区分。

17、对一个类的所有对象而言,有时需要共享数据,可以将类对象需要共享的数据定义为全局变量,以实现数据共享。但是编程时要注意避免与其他全局变量的名字冲突,而且全局变量可以被任何函数所修改。为了实现类对象的数据共享并避免前面所述的问题,可以使用类的静态数据成员和静态成员函数。声明静态数据成员和静态成员函数的关键字是static。

  ⑴类的静态数据成员独立于具体的对象,但又与每个对象有关,可以通过对象来访问。

  ⑵对静态数据成员的定义与初始化应在类外进行,通常在类声明之后,主函数main()之前进行。

  ⑶在定义和初始化静态数据成员时,不能在前面添加关键字static。

  ⑷静态数据成员同静态变量一样,在编译时就被创建和初始化。对于公有的静态数据成员,可以在定义对象之前进行访问,而对于私有的静态数据成员,不能直接进行访问。

  ⑸静态成员函数的主要作用是访问静态数据成员。通过静态成员函数,可以在对象建立之前进行静态数据成员的访问。静态成员函数不属于某一个具体的对象,是属于类的。

  ⑹静态成员函数的声明形式为:static 返回类型静态成员函数名(参数表);

    当静态成员函数时公有成员函数时,主要有三种调用方式:类名::静态成员函数名(实参表),对象名.静态成员函数名(实参表),对象指针名->静态成员函数(实参表)

  ⑺静态成员函数与非静态成员函数的主要区别在于:非静态成员函数有this指针参数,而静态成员函数没有this指针参数。因此静态成员函数不能直接访问非静态成员,而应通过对象、对象指针或对象引用间接进行访问。

18、能够对类的私有成员直接进行访问的外部函数或外部类称为友元。声明友元的关键字是friend。

  ⑴类的友元函数可以是非成员函数,也可以是另一个类的成员函数。

  ⑵可以将一个类作为另一个类的友元,称为友元类。一个友元类的所有成员函数都可以访问该类的所有成员。

  ⑶友元提高了程序的运行效率,实现了类与其外部的数据共享。但是,友元破坏了类的封装性,这是与面向对象编程的思想相背离的,因此,使用友元时要谨慎。

  ⑷友元关系是单向的,不具备交换性和传递性。

  ⑸当调用友元函数时,需要通过实参指定要访问的对象,该实参可以是对象、对象指针或者对象引用。

  ⑹对友元的说明可以出现在类声明的任何地方,不受访问权限控制符的影响。

19、类中的数据成员可以是基本数据类型,也可以是类这样的复合数据类型。在一个类的数据成员中包含另一个类的对象称为类的组合。这个被包含的对象称为对象成员或子对象。

  ⑴含有对象成员的类可表示为:class 类名{……访问权限控制符:类名1 对象名1;类名2 对象名2……}

  ⑵类的构造函数通常可表示为:类名::类名(形参表0):对象成员1(参数表1),……{……},先调用对象成员的构造函数进行对象成员的初始化,再进行其他类成员的初始化。如果对象成员有带参数的构造函数但是没有默认构造函数,则必须通过构造函数初始化表完成初始化。