设为首页 加入收藏

TOP

C++多态解析
2016-12-06 20:24:41 】 浏览:233
Tags:解析

因为,我们编写代码时,有的时候,当对象不同时,就需要调用不同的函数。在这个时候就需要使用的多态了。

再说类的多态性之前我先来说说对象这个概念。

对象的类型

对象的概念可以分为两种类型

所谓的静态类型,就是一般的类型 。。。

而动态类型,举个例子来说就像是赋值兼容规则里说的

一个基类对象可以用 派生类对象来赋值;在这里的这个对象就是动态类型的。

因为只有在运行时调用对象时 才知道调用的实际上是一个派生类的对象。。。

多态

多态概念:多态这一特性,用通俗的话来说就是 一个事物在不同的时候表现为多种状态。。。。

但是在C++中多态有这更为广泛的含义

静态多态

所谓静态多态,指的是编译器在编译期间完成的,编译器根据函数实参的类型(可能会进行隐式类型转换),可推
断出要调用那个函数,如果有对应的函数就调用该函数,否则出现编译错误。

函数重载,编译器在编译时,就已经判断出参数的类型 ,根据类型的不同来调用不同的函数。

模板 ,也如函数重载一般,根据模板参数的不同调用函数。

函数重载例子:

关于模板的示例可以看看我之前写的C++函数模板

动态多态

动态绑定指的是在程序执行期间(非编译期)判断所引用对象的实际类型,根据其实际类型调用相应的方法。

在这里我们动态多态讲的主要是 说 虚函数

虚函数

使用virtual关键字修饰类的成员函数时,指明该函数为虚函数,派生类需要重新实现,编译器将实
现动态绑定。

下面来举个虚函数的示例:

class B
{
public:
	 virtual void Base()
	{
		cout << "void B::Base()" << endl;
	}
};
class D:public B
{
public:
	void Base()
	{
		cout << "void D::Base()" << endl;
	}
};
int main()
{
	B b;
	D d;
	B* b1 = &d;
	b.Base();
	b1->Base();
	d.Base();
	return 0;
}
代码执行结果:


从输出的结果上我们看出

	b.Base();//调用的是基类的函数
	b1->Base();//调用的是派生类的函数
	d.Base();//调用的是派生类的函数
函数调用时b1调用的是对象d内存,所以调用的是派生类的函数;;;;

【动态绑定条件】
1、必须是虚函数
2、通过基类类型的引用或者指针调用虚函数

下面说说在多态中 我们可能会遇到几种函数名相同的情况:

1、函数重载

限定条件为:

1)在同一作用域内;(一定要记住这一点)

2)函数名相同;

3)参数列表相同(参数的顺序 ,类型 ,长度)

2、同名隐藏

限定条件为:

1)一个在基类中,一个在派生类里;

2)函数名相同;

3、函数重写

限定条件为:

1)一个在基类中,一个在派生类里

2)都是虚函数;

3)函数原型相同(函数名,参数,返回值相同)

4、协变

限定条件为:

1)一个在基类中,一个在派生类里

2)都是虚函数

3)函数名相同,参数列表相同

4)函数返回值分别为基类的指针(引用),派生类类的指针(引用)

下面有一段代码我们来看看

class B
{
public:
	virtual	void Test1(int _test){ cout << "B::Test1()" << endl; }
			void Test2(int _test){ cout << "B::Test2()" << endl; }
			void Test3(int _test){ cout << "B::Test3()" << endl; }
	virtual	B* Test4(int _test1, int _test2)
	{
		cout << "B::Test4()" << endl; 
		return  this;
	}
};   
class D :public B
{
public:
	virtual	void Test1(int _test){ cout << "D::Test1()" << endl; }
	virtual	void Test2(int _test){ cout << "D::Test2()" << endl; }
			void Test3(int _test){ cout << "D::Test3()" << endl; }
	virtual	D* Test4(int _test1, int _test2)
	{
		cout << "D::Test4()" << endl;
		return this;
	}
};

上述代码中

Test1()属于函数重写

Test2()属于虚函数

Test3()属于同名隐藏

Test4()属于协变

纯虚函数

所谓纯虚函数

在成员函数的形参后面写上=0,则成员函数为纯虚函数。

包含纯虚函数的类叫做抽象类(也叫接口类),抽象类不能实例化出对象。纯虚函数在派生类中重新定义以后,派生类才能实例化出对象。

用代码来直观说明一下吧

class Base
{
public:
	virtual  void Test() = 0;//纯虚函数
	int _b;
	
};
class Derived :public Base
{};

在这段代码中,Base就是一个抽象类,而Test函数就是一个纯虚函数

所以,不能使用Base类 来定义一个对象 。

那些函数可以定义为虚函数呢?????

总结一句话就是 只有类的非静态成员函数才能定义为虚函数

但是类的构造函数不能定义为虚函数,因为构造函数是在类对象创建时调用的,

而虚函数是通过基类的指针和派生类的指针和引用调用的,

如果将构造函数定义为虚函数,无法正常实现虚函数与构造函数的功能。

一般情况下,要将基类析构函数定义为虚函数,为什么呢???

class Base
{
public:
	Base();
	virtual  ~Base();
};
class Derived :public Base
{
public:
	Derived();
	~Derived();
};
当声明一个基类的引用 ,用派生类赋值
int mian()
{
	Derived  d;
	Base &rb = d;
	return 0;
}

当函数结束后 ,rb类析构时,应该调用的派生类的析构函数,所以应该将基类的析构函数定义为虚函数,

来根据参数的不同调用不同的析构函数;

至于为什么只有非静态的成员函数才能定义 成虚函数??

我还没搞清楚》》》之后再研究研究

下面是对上面所说的虚函数编写时所要注意的地方(对上面的总结)

1、派生类重写基类的虚函数实现多态,要求函数名、参数列表、返回值完全相同。(协变除外)

2、基类中定义了虚函数,在派生类中该函数始终保持虚函数的特性。(就像是上面说的函数Test2)

3、关于哪些函数可以定义为虚函数,只有类的非静态成员函数才能定义为虚函数,静态成员函数不能定义为虚函数。(构造函数除外 )

4、构造函数不能定义为虚函数,虽然可以将operator=定义为虚函数,但最好不要这么做,使用时容
易混淆

5、如果在类外定义虚函数,只能在声明函数时加virtual关键字,定义时不用加(声明和定义只在一个地方加上virtual)

6、不要在构造函数和析构函数中调用虚函数,在构造函数和析构函数中,对象是不完整的,可能会
出现未定义的行为。(因为虚函数是通过虚表来调用的,构造与析构时,对象不完整)。

7、最好将基类的析构函数声明为虚函数。(析构函数比较特殊,因为派生类的析构函数跟基类的析构
函数名称不一样,但是构成覆盖,这里编译器做了特殊处理)

】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇C++构造函数中遇到的问题 下一篇C++:findLargestBlock寻找最大块

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目