虚函数和虚基类的区别
C++虚函数,纯虚函数,抽象类以及虚基类的区别
Part1.C++中的虚函数
什么是虚函数:
直观表达就是,如果⼀个函数的声明中有 virtual 关键字,那么这个函数就是虚函数。
虚函数的作⽤:
虚函数的最⼤作⽤就是实现⾯向对象程序设计的⼀⼤特点,多态性,多态性表达的是⼀种动态的概念,是在函数调⽤期间,进⾏动态绑定,以达到什么样的对象就实现什么样的功能的效果。
虚函数的⼀般声明语法:
virtual 函数类型函数名 (形参表)
注意:
虚函数的声明只能出现在类的定义中,不能出现在成员函数实现的时候
虚函数⼀般不声明为内联函数,但是声明为内联函数也不会引起错误
在运⾏过程中要实现多态的三个条件:
类之间满⾜赋值兼容关系(也就是类之间有继承关系)
要声明为虚函数
调⽤虚函数时,要由成员函数或者是指针和引⽤来访问
代码举例
#include <iostream>
using namespace std;
class Base1 {
public:
public:
virtual void play();
};
void Base1::play()
{
cout << "Base1::play()" << endl;
}
class Base2:
public Base1
{
virtual void play();
};
void Base2::play() {
cout << "Base2::play()" << endl;
}
class Derived :
public Base2
{
virtual void play();
};
void Derived::play() {
cout << "Derived:: play()" << endl;
}
void fun(Base1* ba) { //声明⼀个基类的指针
ba->play();
}
int main()
{
Base1 ba1;
Base2 ba2;
Derived de;
//分别⽤不同的对象指针来调⽤ fun 函数
fun(&ba1);
fun(&ba2);
fun(&de);
return 0;
}
这代码含义就充分体现了虚函数作为实现多态条件的原因,由于 Base1 是 Base2 和 Derived 的⽗类,所以,Base1 是可以兼容 Base2 和Derived 的,所以在 fun 函数这⾥是⽤的 Base1 的指针来作为形参,不同的是当我传⼊参数不同时,fun 函数执⾏的是不同的结果,这就体现了多态的效果,我需要那个类型的实例,他就执⾏那个实例对应的⽅法。
需要注意的是:
基类的指针可以指向派⽣类的对象,基类的引⽤可以作为派⽣类的别名,但是基类的对象不能表⽰派⽣类的对象,所以在 fun 函数中我使⽤的是 Base1 的指针(换成引⽤也可以),⽽不是 Base1 的对象。
Part2.纯虚函数和抽象类
纯虚函数⼀般是和抽象类⼀起使⽤的,因为抽象类的定义就是:拥有纯虚函数的类是抽象类,所以需要先了解⼀下纯虚函数。
什么是纯虚函数
在虚函数的声明基础上,在函数声明后⾯加上 =0,的函数为纯虚函数
⼀般定义语法:
virtual 函数类型函数名(参数表)=0;
什么时候使⽤纯虚函数:
当⼀个⽅法不⽤实例化
⽅法的实现必须在派⽣类中
多态性与虚函数注意:
纯虚函数不⽤被实现
区分纯虚函数和函数体为空的函数,这是两中不同的函数
抽象类:
抽象类的主要作⽤:
为⼀个类族建⽴起⼀个公共的接⼝,使他们能够完整发挥多态的特性
注意:
抽象类不能实例化
代码举例
#include <iostream>
using namespace std;
class Base1 {
public:
public:
virtual void play()=0;
};
void Base1::play()
{
cout << "Base1::play()" << endl;
}
class Base2:
public Base1
{
virtual void play();
};
void Base2::play() {
cout << "Base2::play()" << endl;
}
class Derived :
public Base2
{
virtual void play();
};
void Derived::play() {
cout << "Derived:: play()" << endl;
}
void fun(Base1* ba) { //声明⼀个基类的指针
ba->play();
}
int main()
{
Base2 ba2;
Derived de;
//分别⽤不同的对象指针来调⽤ fun 函数
fun(&ba2);
fun(&de);
return 0;
}
这段代码和上⾯的代码区别不⼤,唯⼀的区别在于,将 Base1 的 play⽅法声明为了纯虚函数,所以 base1 成了⼀个抽象类,就不能在直接声明⼀个 Base1 类型的对象,如果在声明⼀个纯虚函数,编译器就会报错,因为抽象类不能被实例化。
Part3.虚基类
之所以把虚基类放到这⾥为了做⼀个⽐较,因为学习了虚函数,抽象类后容易把这⼏个概念弄混,所以在这⾥对⽐记忆。
为什么要使⽤虚基类
#include <iostream>
using namespace std;
class A {
public :
int varA;
};
class B:
public A
{
public:
int varB;
};
class C:
public A
{
public:
int varC;
};
class D :
public C, public B
{
public:
int varC;
};
int main()
{
D d;
d.varA;
return 0;
}
解析上⾯的代码,由于对象 D 是继承与 B 和 C的,然⽽ B 和 C ⼜共同继承与 A,所以 B 和 C都具有从 A 中继承下来的属性 varA,所以我可以⽤ d 对象来调⽤ varA ,但是正是因为 B 和 C 中都具有 varA,所以我⽤
d 对象调⽤ varA 时,编译器会产⽣疑问,到底是调⽤的 B 的 varA 还是 C 的 varA,这样就会产⽣错误,当然我们可以使⽤作⽤域分辨符来区分到底是谁的 varA,但是这样就不能很好的体现继承的概念了,所以这⾥使⽤虚基类来解决这个问题。
虚基类的作⽤
当⼀个派⽣类中有多个直接基类,⽽这些直接基类⼜有⼀个共同的基类,则在最终的派⽣类中会保留该间接基类的数据成员的多份同名成员,就会造成⼆义性,将这个共同基类设置为虚基类时,同名的数据成员就会只存在⼀个副本,同⼀个函数名只有⼀个映射,就解决了⼆义性。
也就是说,当声明为虚基类时,在程序中只保留了⼀个共同基类的数据副本,对象 B 和对象 C 的 varA 都指向同⼀个 varA(本来也应该是
这样),这样再调⽤ varA 时,在程序中只有⼀个 varA,编译器就不会产⽣疑问了。
基本语法
class A {
public :
int varA;
};
class B:
virtual public A
{
public:
int varB;
};
class C:
virtual public A
{
public:
int varC;
};
class D :
public A, public B
{
public:
int varC;
};
Part4.总结
虚函数,是在类中中的概念,他的重要作⽤就是实现⾯向对象的多态的特性,
抽象类,是类的概念,他必须和纯虚函数函数搭配使⽤
虚基类,是继承中的概念,是继承过程中⽤来解决多个间接基类同⼀个副本产⽣的⼆义性的⽅法。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论