彻底搞懂C++多态虚函数等问题

1.继承和覆写

子类继承父类,子类可以覆写基类的函数。当然,直接生成一个子类的对象,用子类的指针操作是没有问题的。调用的函数是子类的函数,即覆写后的。

// ConsoleApplication3.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <iostream>
using namespace std;

class Base
{
public:
	Base(void)
	{
		cout<<"Base is created"<<endl;
	}
	virtual ~Base(void)
	{
		cout<<"Base destroyed!"<<endl;
	}
	void func()
	{
		cout<<"Base function is called"<<endl;
	}
};

class Demo : public Base
{
public:
	Demo(void)
	{
		cout<<"Demo is created"<<endl;
	}
	~Demo(void)
	{
		cout<<"Demo destroyed!"<<endl;
	}

	void func()
	{
		cout<<"Demo function is called"<<endl;
	}
};

int _tmain(int argc, _TCHAR* argv[])
{

	Demo* demo = new Demo();
	demo->func();

	int a;
	cin>>a;
	return 0;
}

结果:

Base is created

Demo is created

Demo function is called

但是,如果要用父类的指针调用子类的对象呢?还是会调用覆写后的函数吗?

答案是不会。。。

// ConsoleApplication3.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <iostream>
using namespace std;

class Base
{
public:
	Base(void)
	{
		cout<<"Base is created"<<endl;
	}
	virtual ~Base(void)
	{
		cout<<"Base destroyed!"<<endl;
	}
	void func()
	{
		cout<<"Base function is called"<<endl;
	}
};

class Demo : public Base
{
public:
	Demo(void)
	{
		cout<<"Demo is created"<<endl;
	}
	~Demo(void)
	{
		cout<<"Demo destroyed!"<<endl;
	}

	void func()
	{
		cout<<"Demo function is called"<<endl;
	}
};

int _tmain(int argc, _TCHAR* argv[])
{
	Base* base = new Demo();
	base->func();
	//Demo* demo = new Demo();
	//demo->func();
	//delete base;
	int a;
	cin>>a;
	return 0;
}

Base is created

Demo is created

Base function is called

那么要肿么办呢?

下面就是多态的方法啦。

2.关于多态

多态实际上就是用基类的指针来操作子类的对象。但是上面覆写了之后,却调用的还是父类的函数。要解决这个问题就要加一个关键字,virtual。

就是这一个关键字就改变了程序运行的结果。

// ConsoleApplication3.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <iostream>
using namespace std;

class Base
{
public:
	Base(void)
	{
		cout<<"Base is created"<<endl;
	}
	virtual ~Base(void)
	{
		cout<<"Base destroyed!"<<endl;
	}
	void virtual func()
	{
		cout<<"Base function is called"<<endl;
	}
};

class Demo : public Base
{
public:
	Demo(void)
	{
		cout<<"Demo is created"<<endl;
	}
	~Demo(void)
	{
		cout<<"Demo destroyed!"<<endl;
	}

	void func()
	{
		cout<<"Demo function is called"<<endl;
	}
};

int _tmain(int argc, _TCHAR* argv[])
{
	Base* base = new Demo();
	base->func();
	//Demo* demo = new Demo();
	//demo->func();
	//delete base;
	int a;
	cin>>a;
	return 0;
}

在要被覆写的基类函数前面加上virtual关键字就可以使父类指针调用子类对象的重写的函数。

结果:

Base is created

Demo is created

Demo function is called

但是还有一种情况,就是即使覆写了父类的函数,但仍然需要父类的函数的功能,这要肿么办呢?

最开始我的想法是从父类的Ctrl+c 然后Ctrl+v过来。后来一想,这个也忒麻烦了吧,而且不利于代码的维护。还好,有这样一个简单的方法。

在子类覆写的函数中,加上这句

Base::func();

即调用了父类的函数,然后再加上子类特有的功能即可。

// ConsoleApplication3.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <iostream>
using namespace std;

class Base
{
public:
	Base(void)
	{
		cout<<"Base is created"<<endl;
	}
	virtual ~Base(void)
	{
		cout<<"Base destroyed!"<<endl;
	}
	void virtual func()
	{
		cout<<"Base function is called"<<endl;
	}
};

class Demo : public Base
{
public:
	Demo(void)
	{
		cout<<"Demo is created"<<endl;
	}
	~Demo(void)
	{
		cout<<"Demo destroyed!"<<endl;
	}

	void func()
	{
		Base::func();
		cout<<"Demo function is called"<<endl;
	}
};

int _tmain(int argc, _TCHAR* argv[])
{
	Base* base = new Demo();
	base->func();
	//Demo* demo = new Demo();
	//demo->func();
	//delete base;
	int a;
	cin>>a;
	return 0;
}

Base is created

Demo is created

Base function is called

Demo function is called

这样就能既使用子类的特有功能,又调用了父类的功能。

3..虚析构函数

如果是基类,没有定义为虚析构函数的话,用基类指针操作子类,不会调用子类对象的析构函数,会导致只释放了基类部分的资源,而定义在子类部分的资源没被释放,造成内存泄露。

// ConsoleApplication3.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <iostream>
using namespace std;

class Base
{
public:
	Base(void)
	{
		cout<<"Base is created"<<endl;
	}
	virtual ~Base(void)
	{
		cout<<"Base destroyed!"<<endl;
	}
};

class Demo : public Base
{
public:
	Demo(void)
	{
		cout<<"Demo is created"<<endl;
	}
	~Demo(void)
	{
		cout<<"Demo destroyed!"<<endl;
	}
};

int _tmain(int argc, _TCHAR* argv[])
{
	Base* base = new Demo();
	delete base;
	int a;
	cin>>a;
	return 0;
}

运行结果:

Base is created

Demo is created

Demo destroyed!

Base destroyed!

子类对象构造时,会先调用父类的构造函数,然后调用子类的构造函数,初始化子类的特有部分。析构时,顺序相反,先调用子类的析构函数,再调用父类的析构函数。

构造函数和析构函数中都是默认调用父类的函数的。不用像上面那样要额外加上调用父类函数的句子。

时间: 2024-11-15 00:51:04

彻底搞懂C++多态虚函数等问题的相关文章

一个例子搞懂C++的虚函数和纯虚函数

转自https://blog.csdn.net/vincent040/article/details/78848322,并对代码做了小幅修正,在此感谢原作者. 学习C++的多态性,你必然听过虚函数的概念,你必然知道有关她的种种语法,但你未必了解她为什么要那样做,未必了解她种种行为背后的所思所想.深知你不想在流于表面语法上的蜻蜓点水似是而非,今天我们就一起来揭开挡在你和虚函数(女神)之间的这一层窗户纸. 首先,我们要搞清楚女神的所作所为,即语法规范.然后再去探究她背后的逻辑道理.她的语法说来也不复

一个例子彻底搞懂C++的虚函数和纯虚函数

学习C++的多态性,你必然听过虚函数的概念,你必然知道有关她的种种语法,但你未必了解她为什么要那样做,未必了解她种种行为背后的所思所想.深知你不想在流于表面语法上的蜻蜓点水似是而非,今天我们就一起来揭开挡在你和虚函数(女神)之间的这一层窗户纸. 首先,我们要搞清楚女神的所作所为,即语法规范.然后再去探究她背后的逻辑道理.她的语法说来也不复杂,概括起来就这么几条: 1.在类成员方法的声明(不是定义)语句前面加个单词:virtual,她就会摇身一变成为虚函数: 2.在虚函数的声明语句末尾中加个 =0

多态&amp;虚函数

(1).对象类型: a.静态类型:对象声明时的类型,编译的时候确定 b.动态类型:对象的类型是运行时才能确定的 class A {}; class B:public A {}; int main() { B* b; A* a=b;//a的静态类型是A*,动态类型(运行时)类型是B* return 0; } (2).多态 a.静态多态:函数重载.泛性编程 int Add(int a,int b) { return a+b; } float Add(float a,float b) { return

VS之多态虚函数的实现

本文简单地介绍下如何使用多态和虚函数实现程序的调用. 使用工具:VS2008 使用语言:C++ 开发步骤: 1.新建对话框程序 2.添加基类,写一个虚函数 Person.h #pragma once class CPerson { public: CPerson(void); ~CPerson(void); public: virtual void Eat(); }; Person.cpp #include "StdAfx.h" #include "Person.h"

OOP 多态/虚函数

// main.cpp // OOP // 虚函数允许继承层次结构中绝大多数特定版本的成员函数被选择执行,虚函数使多态成为可能. // Created by mac on 2019/4/8. // Copyright ? 2019年 mac. All rights reserved. #include <iostream> using namespace std; class Class1{ public: Class1(){} ~Class1(){} virtual void f(){ co

【继承与多态】C++:继承中的赋值兼容规则,子类的成员函数,虚函数(重写),多态

实现基类(父类)以及派生类(子类),验证继承与转换--赋值兼容规则: 子类对象可以赋值给父类对象(切割/切片) 父类对象不能赋值给子类对象 父类的指针/引用可以指向子类对象 子类的指针/引用不能指向父类对象(可以通过强制类型转换完成) #include<iostream> using namespace std; class People    //父类或者基类 { public:     void Display()     {         cout << "_na

虚函数和多态

虚函数和多态 - 虚函数 在类的定义中,前面有virtual类关键字的成员函数就是虚函数 class base{ virtual int get(); }; int base::get(){} virtual关键字只用在类定义里的函数声明,写函数体时不用 构造函数和静态成员函数不能是虚函数 虚函数可以参与多态,普通函数不能 - 多态的表现形式一 派生类的指针可以赋给基类指针 通过基类指针指向一个基类和派生类中的同名虚函数时 若该指针指向一个基类对象,那么被调用的是基类的虚函数 若该指针指向一个派

一口气搞懂《虚函数和纯虚函数》

学习C++的多态性,你必然听过虚函数的概念,你必然知道有关她的种种语法,但你未必了解她为什么要那样做,未必了解她种种行为背后的所思所想.深知你不想在流于表面语法上的蜻蜓点水似是而非,今天我们就一起来揭开挡在你和虚函数(女神)之间的这一层窗户纸. 首先,我们要搞清楚女神的所作所为,即语法规范.然后再去探究她背后的逻辑道理.她的语法说来也不复杂,概括起来就这么几条: 在类成员方法的声明(不是定义)语句前面加个单词:virtual,她就会摇身一变成为虚函数. 在虚函数的声明语句末尾中加个 =0 ,她就

虚函数与多态小览

一.文章来由 Bill又写文章来由了哇~~早就想好好搞清这个问题了,这是c++领域里面比较难搞定的一块知识点,而且最近在看设计模式,里面有涉及这块,之前学过的不用容易玩忘记,于是就干脆研究透一点,也好碰到.用到的时候不心慌~于是有了这篇文章. 二.从编译时和运行时说起 2.1 编译时: 顾名思义就是正在编译的时候.就是编译器帮你把源代码翻译成机器能识别的代码.(当然只是一般意义上这么说,实际上可能只是翻译成某个中间状态的语言.比如Java只有JVM识别的字节码,C#中只有CLR能识别的MSIL)