多态是什么

》多态定义的概念是:当不同的对象收到相同的消息时做出了不同工作这种现象就叫做多态。

》那么在C++中是如何实现多态的呢?

首先多态分为编译时多态和运行时多态。在这里还有一个连编的概念,连编即把函数名和函数体中的代码连接在一起的过程。静态连编就是在编译阶段完成的连编,编译时多态就是通过静态连编完成的。静态连编时,系统通过实参与形参进行匹配,对于同名的重载函数就根据参数上的差异进行区分,然后进行连编,从而实现多态性。运行时多态使用动态连编实现的,动态连编是指运行阶段完成的连编。即当程序调用某一个函数名时,才去寻找和连接其相对应的程序代码。

在C++中,编译时多态性主要是通过函数重载和运算符重载实现的,运行时多态性主要是通过虚函数来实现的。

虚函数的引入:

class Base
{
public:
Base(int x,int y)
:a(x)
,b(y)
{}
void show()
{
cout << "Base----" << endl;
cout << a << " " << b << endl;
}
private:
int a;
int b;
};
class Deriver :public Base
{
public:
Deriver(int x, int y, int z)
:c(z)
,Base(x,y)
{}
void show()
{
cout << "Deriver----" << endl;
cout << c << endl;
}
private:
int c;
};
void main()
{
Base mb(60, 60), *pc;
Deriver mc(10, 20, 30);
pc = &mb;
pc->show();
pc = &mc;
pc->show();
}

结果如下:

并不是我们所预想的,这说明,不管指针pc当前指向哪个对象(基类的或派生类的),“pc->show()”调用的都是基类定义的show()函数。

》虚函数的作用和定义:

虚函数首先是基类的成员函数,但这个成员函数前面加上关键字virtual.并在派生类中被重载,就能实现动态调用的功能。

class Base
{
public:
Base(int x,int y)
:a(x)
,b(y)
{}
virtual void show()
{
cout << "Base----" << endl;
cout << a << " " << b << endl;
}
private:
int a;
int b;
};
class Deriver :public Base
{
public:
Deriver(int x, int y, int z)
:c(z)
,Base(x,y)
{}
void show()
{
cout << "Deriver----" << endl;
cout << c << endl;
}
private:
int c;
};
void main()
{
Base mb(60, 60), *pc;
Deriver mc(10, 20, 30);
pc = &mb;
pc->show();
pc = &mc;
pc->show();
}

结果:

为什么把基类中的函数show()定义为虚函数时,程序的运行结果就正确了呢?这是因为,关键字virtual指示C++编译器,函数调用“pc->show()”时,要在运行时确定所要调用的函数即要对该调用进行动态连编。我们把使用同一种调用形式“mp->show()”,调用同一类族中不同类的虚函数称为动态的多态性,即运行时多态性。

》虚函数的定义

virtual 返回类型 函数名(形参表)

{   函数体

}

》虚析构函数

class Base
{
public:
~Base()
{
cout << "调用基类Base的析构函数" << endl;
}
};
class Deriver:public Base
{public:
~Deriver()
{
cout << "调用派生类Deriver的析构函数" << endl;
}
};
int main()
{
Base* p;
p = new Deriver;
delete p;
return 0;
}

结果:

这里创建了一个派生类的无名对象用基类的指针指向他,在delete指针时只调用了基类的析构函数没有调用派生类的析构函数原因是当撤销指针p所指的派生类的无名对象,而调用析构函数时,采用了静态连编方式,只调用了基类的析构函数。

如果希望程序执行采用动态连编方式,可以将基类的析构函数声明为虚析构函数。

virtual ~类名()

{函数体

};

虽然基类和派生类析构函数的名字不同,但是如果将基类析构函数定义为虚函数,基类派生的所有派生类析构函数也都自动声明为虚析构函数。

class Base
{
public:
virtual ~Base()
{
cout << "调用基类Base的析构函数" << endl;
}
};
class Deriver:public Base
{public:
~Deriver()
{
cout << "调用派生类Deriver的析构函数" << endl;
}
};
int main()
{
Base* p;
p = new Deriver;
delete p;
return 0;
}

结果:

当基类析构函数声明为虚析构函数时结果就符合我们所期望的,这是由于virtual关键字要求delete p时进行动态连编,先调用派生类析构函数再调用基类析构函数实现动态运行时多态。

》多继承与虚函数

C++语言中,每个有虚函数的类或者虚继承的子类,编译器都会为它生成一个虚拟函数表(简称:虚表),表中的每一个元素都指向一个虚函数的地址。(注意:虚表是从属于类的)

此外,编译器会为包含虚函数的类加上一个成员变量,是一个指向该虚函数表的指针(常被称vptr),每一个由此类别派生出来的类,都有这么一个vptr。虚表指针是从属于对象的。也就是说,如果一个类含有虚表,则该类的所有对象都会含有一个虚表指针,并且该虚表指针指向同一个虚表。

虚表的内容是依据类中的虚函数声明次序--填入函数指针。派生类别会继承基础类别的虚表(以及所有其他可以继承的成员),当我们在派生类中改写虚函数时,虚表就受了影响;表中的元素所指的函数地址将不再是基类的函数地址,而是派生类的函数地址。

》纯虚函数与抽象类

声明 virtual 函数类型 函数名(参数表)=0;

含有纯虚函数的类称为抽象类。

那么纯虚函数存在的作用是什么呢?

纯虚函数只是在基类中为其派生类保留一个函数的名字,以便派生类根据需要对它进行重新定义。纯虚函数没有函数体,它的后边“=0”并不表示函数的返回值为0,他只是起形式上的作用,告诉编译系统“这是纯虚函数”,纯虚函数不具备函数的功能,不能被调用。

时间: 2024-11-10 09:33:32

多态是什么的相关文章

C#多态

通过继承,一个类可以用作多种类型:可以用作它自己的类型.任何基类型,或者在实现接口时用作任何接口类型.这称为多态性.C# 中的每种类型都是多态的.类型可用作它们自己的类型或用作 Object 实例,因为任何类型都自动将 Object 当作基类型. 多态性不仅对派生类很重要,对基类也很重要.任何情况下,使用基类实际上都可能是在使用已强制转换为基类类型的派生类对象.基类的设计者可以预测到其基类中可能会在派生类中发生更改的方面.例如,表示汽车的基类可能包含这样的行为:当考虑的汽车为小型货车或敞篷汽车时

Java基础(八):多态

一.多态的理解: 多态是同一个行为具有多个不同表现形式或形态的能力. 多态就是同一个接口,使用不同的实例而执行不同操作,如图所示: 多态性是对象多种表现形式的体现:现实中,比如我们按下 F1 键这个动作:如果当前在 Flash 界面下弹出的就是 AS 3 的帮助文档:如果当前在 Word 下弹出的就是 Word 帮助:在 Windows 下弹出的就是 Windows 帮助和支持:同一个事件发生在不同的对象上会产生不同的结果. 二.多态的优点和必要条件: 多态的优点:1. 消除类型之间的耦合关系2

当this指针成为指向之类的基类指针时,也能形成多态

this指针: 1)对象中没有函数,只有成员变量 2)对象调用函数,通过this指针告诉函数是哪个对象自己谁. 1 #include<iostream> 2 using namespace std; 3 class Shape 4 { 5 public: 6 //void cal_display(Shape* this) 7 void cal_display(){ 8 display(); 9 this->display(); 10 } 11 private: 12 virtual vo

Java多态

多态不是方法的重载,不是方法名一样方法的参数不一样,不是一个参数有多种态度就称之为多态,那是不正确的,如果这就是多态的话那么何必有方法的重载?直接改名多态就行了.父类 a = 子类对象 就是子类对象可以披上父类的衣服,只要穿上了父类的衣服就装扮成了父类 可以做父类的一些事情灵活性强.多态最重要的目的就是为了让子类转换成父类. 面向对象编程之上还有一种叫做面向功能编程,面向功能编程还可以转换成面向父类编程.比如:现实生活中,有小宝.大宝 大宝是小宝的父亲.有一天大宝不在家,小宝接到打给大宝的电话

C++中多态的实现原理

1. 用virtual关键字申明的函数叫做虚函数,虚函数肯定是类的成员函数. 2. 存在虚函数的类都有一个一维的虚函数表叫做虚表.类的对象有一个指向虚表开始的虚指针.虚表是和类对应的,虚表指针是和对象对应的. 3. 多态性是一个接口多种实现,是面向对象的核心.分为类的多态性和函数的多态性. 4. 多态用虚函数来实现,结合动态绑定. 5. 纯虚函数是虚函数再加上= 0. 6. 抽象类是指包括至少一个纯虚函数的类. 纯虚函数:virtual void breathe()= 0:即抽象类!必须在子类实

OC多态

多态:不同对象以自己的方式响应相同的消息的能力叫做多态. 由于每个类都属于该类的名字空间,这使得多态称为可能.类定义中的名字和类定义外的名字并不会冲突.类的实例变量和类方法有如下特点:和C语言中结构体中的数据成员一样,类的实例变量也位于该类独有的名字空间.类方法也同样位于该类独有的名字空间.与C语言中的方法名不同,类的方法名并不是一个全局符号.一个类中的方法名不会和其他类中同样的方法名冲突.两个完全不同的类可以实现同一个方法.方法名是对象接口的一部分.对象收到的消息的名字就是调用的方法的名字.因

多态的内存分析-转载

java运行时,在内存里分四个部分.栈,堆,数据区和代码区..举个例子String str=new String("AAA");str就放在栈里,字符串"AAA"放在堆里.所有的方法代码都放在了代码区. public class A{public void show(){System.out.println("A");}} public class B extends A{public void show(){System.out.println

多态and接口

一.多态 1.什么是多态? 解析:不同的对象对于同一个操作,做出的响应不同 具有表现多种形态的能力的特征 2.使用多态的优点 解析:为了实现统一调用 一个小例子:<父类类型作为参数> 父类(Pet) 子类(Gog,Penguin) 主人类(Master)测试类(Test) Pet public abstract class Pet { public abstract void eat(); } Dog public class Dog extends Pet{ @Override public

初始继承和多态

一.子类与父类 1.子类:父类 例如: Dog(子类):Anomal(父类) 子类(派生类)父类(基类和超类) 2.子类可以继承父类那些成员 (非私有成员,但是从技术角度,可以认为是父类的所有成员) 软件系统中的两个类符合is a时可以使用继承 例如: student is a person se is a employee 鸵鸟(ostrish)is a bird(错误结论!!!) ☆:继承模式下子类构造背后到底发生了什么? 如果我们想构建一个子类对象 //在Animal父类中 class A

2、C#面向对象:封装、继承、多态、String、集合、文件(上)

面向对象封装 一.面向对象概念 面向过程:面向的是完成一件事情的过程,强调的是完成这件事情的动作. 面向对象:找个对象帮你完成这件事情. 二.面向对象封装 把方法进行封装,隐藏实现细节,外部直接调用. 打包,便于管理,为了解决大型项目的维护与管理. 三.什么是类? 将相同的属性和相同方法的对象进行封装,抽象出 “类”,用来确定对象具有的属性和方法. 类.对象关系:人是类,张三是人类的对象. 类是抽象的,对象是具体的.对象可以叫做类的实例,类是不站内存的,对象才占内存. 字段是类的状态,方法是类执