您的位置:首页 > 编程语言 > C语言/C++

C/C++类与面向对象

2017-07-04 16:12 92 查看
oop(面向对象编程)最重要的特性:

抽象

封装和数据隐藏

多态

继承与派生

代码的可重用性

抽象是对具体对象进行概括,抽出这类对象的公共性质并加以描述的过程

数据抽象:描述某类对象的属性或状态(对象相互区别的物理量)

行为抽象:描述某类对象的共有的行为特征或具有的功能

封装;将抽象出的数据成员、代码成员相结合,将他们视为一个整体。

目的是为了增强安全性和简化编程。使用者不必了解具体细节,而只需要通过外部接口, 以特定的访问权限

继承:继承父类的属性。

派生:相对于父类,自己独有增加的属性

多态性:同一个名称,不同功能的实现方式。

目的:达到行为标识统一,减少程序中标识符的个数

实现:重载函数(静态多态)和虚函数(动态多态)

类:

类是具有相同属性和行为的一组对象的集合,他为属于该类的全部对象提供了统一的抽象描述,其内部包括属性(数据抽象)和行为(行为抽象)两个主要的部分。

利用类可以实现数据的封装、隐藏、继承与派生

利用类易于编写大型复杂程序,其模块化程度比c的函数更高;

函数是将逻辑上相关的语句与数据封装,用于完成特定的功能;

而类则是逻辑上相关的函数(成员函数)与数据(数据成员)的封装,它是对所要处理的问题的描述。

类是一种用户自定义类型,声明形式

Class 类名称

{

Public:

公有成员(外部接口);

Private:

私有成员;

Protected:

保护型成员;

};//注意分号

公有类型成员:在关键字public后面声明,任何外部的函数都可以访问。

私有类成员:关键字private后面声明,只允许本类的函数访问;

如果没声明是什么类型的,写在类下面默认是private的。

保护类型:关键字protected,与private类似,其差别表现在继承与派生时对派生类的影响不同

::作用域解析运算符

在类里面声明的函数(定义了)默认看成内联成员函数。(隐式声明为内联函数)

还可以在类外面使用inline显示声明为内联函数

空类占一个字节

类的对象是该类的某一特定实体,即类 类型的变量。

声明形式: 类名 对象名

类中成员互访

:直接使用成员名

类外访问:使用“对象名.成员名”的方式访问public的成员。

结构与类区别:类中成员的缺省存储属性为私有的

结构体中的缺省存储属性为公有的

c中struct表示结构体

C++中struct(也可以定义类)跟class差不多,只是成员默认访问权限(缺省存储属性)不同

This指针:表示指向该类当前对象的指针,*this表示当前对象,类 类型的指针,this->成员名

或者(*this).成员名

一个空类:系统会默认创建四种成员函数:

1.构造函数2.拷贝构造函数3.析构函数4.赋值函数

给类对象初始化:

1.直接赋值

2.通过公有的成员函数初始化

3.构造函数

4.成员初始化列表

构造函数; 类名(形参表);//声明,允许构造函数为内联函数

1.函数名和类名相同

2.无函数返回类型说明(void都不能有),也没有返回值

3.一个新对象建立时,该类的构造函数自动被调用,对这个对象完成初始化工作

定义:类名::类名()

{;}

构造函数私有化,创建对象:1.通过类的友元函数访问构造函数

2.通过静态成员函数(返回类型是类类型的指针)访问私有构造函数

构造函数带默认缺省形参值,创建对象时可以不写括号,写括号一定要带参数

Point point;

Point point();//报错

Point point(1,2);

析构函数:析构函数是专门用来在对象的生存期结束时做善后工作的。()

1.析构函数名一律为 ~类名

2.没有返回类型

3.没有参数

4.一个类只可以有一个析构函数,可以缺省

5.在对象生存期结束时,包括用delete释放动态对象时,系统自动调用析构函数

6.没有显式声明析构函数时,系统默认创建一个

后创建的先析构,先创建的后析构;

拷贝构造函数

类名::类名(const 类名 & 引用名);

1.

Hero hero_0;

Hero hero_1(hero_0);//显式调用拷贝构造函数

隐式调用

Hero hero_2=hero_1;//隐式调用拷贝构造函数

2.当函数的形参为类对象时,调用函数时或者进行实参和形参结合时。

Void test(Hero hero_1)//实参赋给形参时,自动调用拷贝构造函数
{cout<<hero_1.getHp()<<endl;}
Hero hero_0;


3.当函数返回值为类对象时,函数调用完成返回时。

Hero &newtest()

{

Hero chero;

Return chero;}//返回一个值时系统创建一个临时变量调用拷贝构造函数,返回后释放(调用析构函数)

Hero hero_2=newtest();//这里的Hero hero_2并没有调用构造函数,而是接受函数返回的值

直接返回对象 与 将对象直接作为形参相似,都会产生一个临时副本

Int *p=new int(5);//表示*p=5

成员初始化列表

一些特殊情况下,数据成员只能用初始化,而不能被赋值。

Point::point(float ix,float iy):x(ix) , y(iy)//把ix赋给x,iy赋给y

{ ;}//x(ix) , y(iy)顺序可以打乱

构造函数能对数据成员完成的初始化工作,成员初始化列表都能完成,反之则不一定。

Const数据成员、引用类型的成员 仅能使用成员初始化列表进行初始化

另一个类对象 作为成员时:1.另一个类的数据成员全是public的:

在此类的构造函数对另一个类的对象进行初始化

2.另一个类的数据成员是私有的

使用成员初始化列表初始化该对象

防止头文件多重包含

#ifndef _GHOST_H_
#define _GHOST_H_
{类定义代码块};
#endif


静态成员:前面加个static ,类的静态成员为其所有对象共享,不属于对象(属 于类),不管有多少对象,静态成员只有一份存于内存中。

静态public成员访问: 类名::静态成员名

或者 对象名.静态成员名

静态数据成员默认初始值为0;

在类中说明的静态数据成员属于引用性说明,必须在类的外部(或者类方法实现的文件开头)初始化它(定义性说明)

数据成员类型 类名::静态数据成员 = 初值/表达式;

访问静态成员:1.通过静态成员函数(静态成员函数不能访问非静态数据成员, 但可以访问所有成员函数。非静态成员函数能够访问静态成员)。

2.通过 类名::静态成员名

3.通过 对象名.静态成员名

静态成员函数:没有this指针(因为不属于任何对象),不能使用const

到目前为止,使用static可进行的5种说明有:

局部静态变量

全局静态变量

具有静态存储类别的函数:只能在本文件的内部被调用,其他文件不可见

类的静态数据成员

类的静态成员函数:通常只在其中处理类的静态数据成员

常量成员:const修饰的成员;

常量数据成员在成员说明时不能被赋值,不能通过构造函数初始化,而只能通过构造函数的成员初始化列表的方式来赋值

一旦对象被创建,其常量数据成员的值就不允许被修改。

常量成员函数,只有权读取该类的相应的对象的内容,但无权直接修改他们(const修饰的是this指针)

常量成员函数声明和定义(函数实现)时都要在尾部加上const

作用:1)当函数体较大较复杂时,由系统帮助避免对调用对象内容的修改。

2)当对象被说明为常量对象时,可由系统限制,不让非常量函数成员被调用。(常量对象不能调用非常量成员函数)

友元函数:

关键字friend修饰声明的类的非成员函数,在其函数体中能访问类的private成员和protected成员,还有public成员。

破坏了oop的封装性,数据隐藏性。

增加灵活性,使程序员可以在封装性和快速性做出选择

访问对象中的成员必须通过对象名

一个类的成员函数可以声明为另一个类的友元函数,以便通过一个类的该成员函数访问另一个类的所有成员

友元类:

若一个类为另一个类的友元类,则此类的所有成员函数(包括构造函数
ca5e
和析构函数)都能访问另一个类的所有成员

声明语法:将友元类名在另一个类中使用friend修饰说明

1.友元关系不能传递:B是A的友元,C是B的友元,但C跟A没有友元关系

2.友元关系是单向的:B是A的友元,B能访问A,A不能访问B。

3.友元关系不能继承:父类的友元不是子类的友元。

继承:保持已有类的特性而构造新类的过程

派生:在已有类的基础上新增自己的特性而产生新类的过程

基类(父类) 派生类(子类)

继承的目的:实现代码重用。

派生的目的:当新的问题出现,原有程序无法解决(或不能完全解决)时,需要对原有程序进行改造。

派生类声明:

Class 派生类名:继承方式 基类名

{

};//不写继承方式 默认私有继承,多个继承方式“,”隔开

公有继承:

基类的public和protected在派生类中访问属性不变,但基类的private成员不可访问。

派生类成员函数可以直接访问基类的public成员和protected成员,不能直 接访问基类的private成员(如果函数名重复,派生类访问基类的成员函数时要在基类成员函数前面加上基类作用域)

通过派生类的对象只能访问基类的public成员

私有继承:

基类的public成员和protected成员以private的身份出现在派生类中,但基类的private成员不可访问;

派生类的成员函数可以直接访问基类的public成员和protected成员,不能直接访问基类的private成员

派生类的对象不能访问基类的任何成员,只能访问本类的public成员

保护继承:

基类的public成员和protected成员以protected的身份出现在派生类中,但基类的private不可访问;

派生类的成员函数可以直接访问基类的public成员和protected成员,不能直接访问基类的private成员

通过派生类的对象不能访问基类的任何成员,只能访问本类的public

Protected: 水平访问时,与private成员性质相同(类对象不能访问该类的 protected成员)

垂直访问时,与public成员性质相同(继承)

既实现了数据隐藏,又方便了继承,实现了代码重用

单继承:派生类只从一个基类继承

多继承:派生类从多个基类派生

class 派生类名:继承方式1 基类名1,

继承方式2 基类名2,…

{

成员声明;

}

注意:每一个“继承方式”,只用于限制对紧随其后的基类的继承。(继承方式1 只对基类名1有效)

多重派生:有一个基类派生出多个派生类

多层派生:派生类又作为基类,又派生出新的类

基类的构造函数不被继承,需要在其派生类另行声明

声明派生类构造函数时,只需要对本类中新增成员进行初始化,对继承来的基类成员的初始化由基类完成。

当基类中声明有缺省形式的构造函数或未声明构造函数时,派生类构造函数的定义中可以省略对基类构造函数的调用。

若基类中未声明构造函数,派生类中也可以不声明,全采用缺省形式构造函数(默认构造函数)

当基类声明有带形参的构造函数时,派生类也应声明带形参的构造函数,提供将参数传递给基类构造函数的途径。

构造函数的调用次序:(顺序1->2->3)

1. 调用基类构造函数,调用顺序按照它们被继承时声明的顺序(从左向右)。

2. 调用成员对象(数据成员有对象)的构造函数,调用顺序按照它们在类中 声明的顺序。

3. 派生类的构造函数体中的内容。

继承时的析构函数:

析构函数也不被继承,派生类自行声明。

声明方法与一般(无继承关系时)类的析构函数相同。

不需要显式地调用基类的析构函数,系统会自动隐式调用。

析构函数的调用次序与构造函数相反。

单继承:

派生类的构造函数声明方法:

派生类名(基类形参,派生类形参):基类构造函数{}

多继承:

派生类名(基类1形参,,基类2形参,派生类形参):基类1 构造方法,基类2构造方法{派生类构造函数内容;}

多继承且有内嵌对象时的构造函数

派生类名::派生类名(基类1形参,基类2形参,…基类n形参,本类形参):基类名1(参数), 基类名2(参数), …基类名n(参数),对象数据成员的初始化

{

本类成员初始化赋值语句;

};

两个头文件相互引用时,要在一个类中创建另一个类的对象,这个对象必须是指针,并且要在创建的那个类前面 声明一个 类前声明 class A;

虚基类

虚基类的引入

用于有共同基类的场合

声明

以virtual修饰说明基类

例:class B1:virtual public B

作用

主要用来解决多继承时可能发生的对同一基类继承多次而产生的二义性问题.

为最远的派生类提供唯一的基类成员,而不重复产生多次拷贝

注意:

在第一级继承时就要将共同基类设计为虚基类。

class CZ

{

public:

int cz;

CZ()

{

cz = 3;

}

};

class CA:virtual public CZ

{

public:

int a;

};

class CB:virtual public CZ

{

public:

int a;

};

class CC:public CA,public CB

{

public:

int cc = 3;

};

CC c;

虚基类及其最派生类的构造函数

建立对象时所指定的类为最(远)派生类。

虚基类对于最派生类来说只有一份拷贝。

虚基类的成员是由最派生类的构造函数通过调用虚基类的构造函数进行初始化的。

在整个继承结构中,直接或间接继承虚基类的所有派生类,都必须在其构造函数的成员初始化列表中调用虚基类的构造函数,如果未列出,则表示调用该虚基类的缺省构造函数。

在建立最派生类对象时,只有最派生类的构造函数调用虚基类的构造函数,该派生类的其它基类对虚基类构造函数的调用被忽略。

建立一个对象指针并不会调用类的构造函数,如果动态申请空间的话就会调用构造函数初始化这段内存里面的值。

类的多态:是指发出同样的消息被不同类型的对象接受时导致完全不同的行为

消息:主要指对类的成员函数的调用

静态多态:(编译时的多态)

函数重载

运算符重载

动态多态:(运行时的多态)

虚函数

虚函数:在定义某一基类时,若将其中的某一非静态成员函数属性声明为virtual,就是虚函数

Virtual 返回类型 虚函数名(参数表)

1.虚函数必须是非静态的、非内联的成员函数(因为内联函数在编译时不一定被展开成函数,只是一段代码),而且不能是本类的友元函数,但是虚函数可以在另一个类中被说明为友元函数。

2.虚函数声明只能出现在类定义的函数原型声明中,而不能在成员函数的函数体实现的时候声明。

3.一个虚函数无论被公有继承多少次,它仍然保持其虚函数的特性。

4.若类中一个成员函数被说明为虚函数,则该成员函数在派生类中可能有不同的实现。

5.定义了虚函数后,程序中声明的基类类型的指针就可以指向其派生类。

虚函数的好处

1)可使程序简单易读。

2)它使得程序模块间的独立性加强。

3)增加了程序的易维护性。

4)提高了程序中“信息隐藏”的等级。

成员函数的形参是个常量引用或者指针,则在函数体内不能修改形参对应的数据成员,也不能调用其他普通成员函数。

抽象类:

只要有一个纯虚成员函数的类就是抽象类 虚函数声明后面跟 =0;

基类的成员函数有纯虚函数,则在派生类中必须实现;

抽象类为抽象和设计的目的而建立,将有关的数据和行为组织在一个继承层次结构中,保证派生类具有要求的行为。

对于暂时无法实现的函数,可以声明为纯虚函数,留给派生类去实现。

抽象类只能作为基类来使用,不能创建类对象,但可以创建对象指针和引用

纯虚成员函数的目的:必须在其派生类中对函数进行实现,析构函数一般写成虚函数,但不能写成纯虚函数

虚函数的 限制

(1)只有类的 成员函数才能说明为虚函数,因为虚函数仅适用于继承关系的 类对象,所以普通函数(还有友元函数)不能说明为虚函数。

(2)内联函数不会是虚函数,声明为虚函数后默认不再内联,因为内联函数是在编译时决定其位置。

(3)构造函数不能是虚函数,因为构造对象时对于编译器来说还不知道构造的是什么类型的对象,在运行时才知道调用哪一个,所以构造函数不能是虚函数

(4)析构函数可以是虚函数,而且通常声明为虚函数。

(5)静态成员函数不能是虚函数,因为虚函数是为了多态设计的….静态成员函数独立于对象存在,没有this指针…所以不能设计成虚函数.

(1)当在基类中把成员函数定义为虚函数后,在 其派生类中定义的虚函数必须与基类中的虚函数同名,参数的类型、顺序、个数必须一一对应。

(2)实现这种动态的多态性,必须使用基类类型 的指针变量或引用,使该指针指向不同的派生类的对象,并通过调用指针所指的虚函数才能实现动态的多态性。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息