在C++中同名的函数有三种:
1.重载:又称(重定义) 同名
- 同作用域
- 不同参数(参数类型,参数个数,参数顺序);
#include<iostream>
using namespace std;
void fun(int a,int b)
{
cout<<"int int"<<endl;
}
void fun(double a,double b)
{
cout<<"double double"<<endl;
}
int main()
{
fun(1,2);
fun(1.2,3.5);
return 0;
}
运行结果为:
2.隐藏
派生类中同名函数会隐藏基类中所有的同名函数;
1 父类子类
2 无virtual
3 函数名相同
4 参数可同可不同
#include<iostream>
using namespace std;
class Base{
public:
Base(int a = 20):ma(a)
{
}
void show()
{
cout<<"Bace::show()"<<endl;
}
private:
int ma;
};
class Drive:public Base{
public:
Drive(int b):mb(b),Base(b)
{
}
void show()
{
cout<<"Drive:: show()"<<endl;
}
private:
int mb ;
};
int main()
{
Base b;
b.show();
Drive d(30);
d.show();
Base *ptr = new Drive(50);
Drive*mptr = new Drive(100);
ptr->show();
mptr->show();
return 0;
}
运行结果:
3.覆盖:又称(重写)
基类中同名同参的函数是虚函数
派生类中同名同参的函数是虚函数
派生类中的同名同参的函数覆盖了基类中的同名同参的虚函
1 父类子类
2 函数名相同
3 参数相同
4 基类必须有virtual关键字
#include<iostream>
using namespace std;
class Base
{
public:
Base(int a) :ma(a)
{
std::cout << "Base::Base()" << std::endl;
}
virtual ~Base()
{
std::cout << "Base::~Base()" << std::endl;
}
virtual void Show()
{
std::cout << "Base::Show()" << std::endl;
}
virtual void Show(int a)
{
std::cout << "hello world!" << std::endl;
}
public:
int ma;
};
class Derive :public Base
{
public:
Derive(int b) :mb(b), Base(b)
{
std::cout << "Derive::Derive()" << std::endl;
}
~Derive()
{
std::cout << "Derive::~Derive()" << std::endl;
}
void Show()
{
std::cout << "Derive::Show()" << std::endl;
}
public:
int mb;
};
int main()
{
Base* pb = new Derive(10);
pb->Show();
delete pb;
return 0;
}
运行结果为:
注意:在基类中,我用给析构函数前面加了virtual,如果不添加virtual,那么运行结果为:
我们可以看出,析构函数仅仅调用了基类的构造,没有调用派生类的构造,导致派生类没有释放资源。
虚函数(vritual)
成为虚函数的条件:①能取地址 ②依赖对象调用
虚函数表:
①存放RTTI信息 ②存放偏移 ③虚函数的入口地址
虚函数指针的优先级最高,并且虚函数表在编译阶段产生,存放在.rodata,一个类拥有一个虚表;
- inline函数不能成为虚函数,因为不能取地址
- 普通函数,不能成为虚函数,因为不依赖对象调用
- 构造函数,不能成为虚函数,因为不依赖对象调用。
- 析构函数,可以成为虚函数
- static成员函数,不能成为虚函数,因为不依赖于对象调用。
何为多态?
简单来说,多态是具有表现多种形态的能力的特征,在面向对象中是指,语言具有根据对象的类型以不同方式处理之,特别是重载方法和继承类这种形式的能力。多态被认为是面向对象语言的必备特性。
C++中的虚函数的作用主要是实现了多态的机制。关于多态,简而言之就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数。这种技术可以让父类的指针有“多种形态”,这是一种泛型技术。所谓泛型技术,说白了就是试图使用不变的代码来实现可变的算法。比如:模板技术,RTTI技术,虚函数技术,要么是试图做到在编译时决议,要么试图做到运行时决议。
多态可以分为三类:
- 静多态: 在编译确定调用 静态绑定 早绑定
- 动多态: 在运行确定调用 动态绑定 晚绑定
- 宏多态: 预编译
动多态的发生过时机:
1.指针调用虚函数 2.对象完整
虚表的写入时机:
构造函数的第一行执行代码之前。
对于虚函数和虚继承详细了解的,请参考:深入了解继承与多态(virtual)和C++ 虚继承(虚基类表指针与虚基类表)