C++多态、虚函数

多态

多态的服务对象主要是存在层次结构且是通过继承关联的类。C++的多态意味着调用成员函数时,会根据调用函数的对象的类型来执行不同的函数。

例如:


using namespace std;
class Goust
{
public:
	double i;
    double j;
    Goust(int a, int b)
    {
    	i = a;
		j = b;	
	}
    void put()
    {
    	cout <<"you are"<<i << endl;
	}
};
class Goust1:public Goust
{
	public:
	Goust1(int a,int b):Goust(a,b){}
	void put()
	{
		cout<<"make a"<<j<<endl;
	}
};
class Goust2:public Goust
{
	public:
	Goust2(int a,int b):Goust(a,b){}
	void put()
	{
		cout<<"do a"<<i<<endl;
	}
};
int main()
{
    Goust *g;
    Goust1 h(5,5);
    Goust2 k(6,6);
    g=&h;
    g->put();
    g=&k;
    g->put();
    return 0;
}

输出:

 根据结果可知,两次的输出均未达到想要的效果,输出错误的原因为

调用函数 area() 被编译器设置为基类中的版本,这就是静态多态,也叫静态链接。函数调用在程序执行前就准备好了。

修改方式也就是用多态,关键字为virtual

需修改的部分如下:

class Goust
{
public:
	double i;
    double j;
    Goust(int a, int b)
    {
    	i = a;
		j = b;	
	}
    virtual void put()
    {
    	cout <<"you are"<<i << endl;
	}
};

输出:

 这时候,编译器看的就不再是指针的类型,而是指针的内容。

简单来说,有了多态,就可以在自己的不同类中用相同的函数名称实现不同的功能,甚至于参数也可以是相同的。其实也可以完全避免,就直接在不同的类使用不同的函数名称就好了,主要是为了在复杂的程序函数功能里简单明了。

虚函数

虚函数就是上述关键字virtual声明的函数,也就是在派生类中定义基类中定义的虚函数时,告诉编译器不要静态链接该函数。这种操作官方定义名称为动态链接,也叫后期绑定。

纯虚函数

在一个类中如果存在未定义的虚函数,那么不能直接使用该类的实例,可以理解因为未定义 virtual 函数,其类是抽象的,无法实例化。将报错误:

undefined reference to `vtable for xxx'

在基类并不能给出有意义的实现时,需要用到纯虚函数

表达形式

class Goust
{
public:
	double i;
    double j;
    Goust(int a, int b)
    {
    	i = a;
		j = b;	
	}
    virtual void put()=0;
};

多态形成的三个必要条件:

  • 继承关系
  • 同名虚函数
  • 存在基类类型的指针或者引用,通过该指针或引用调用函数

父类的虚函数或纯虚函数在子类中依然是虚函数。有时我们并不希望父类的某个函数在子类中被重写,这时就要用到关键字final来避免该函数再次被重写。

using namespace std;
class Goust
{
public:
	double i;
    double j;
    Goust(int a, int b)
    {
    	i = a;
		j = b;	
	}
    void put()
    {
    	cout <<"you are"<<i << endl;
	}
};
class Goust1:public Goust
{
	public:
	Goust1(int a,int b):Goust(a,b){}
	void put() final
	{
		cout<<"make a"<<j<<endl;
	}
};
/*class Goust2:public Goust1
{
	public:
	void put()  //错误用法,put在Goust1中已经不是虚函数了,因此不能再被重写。
	{
		cout<<"do a"<<i<<endl;
	}
};*/
int main()
{
    Goust *g;
    Goust1 h(5,5);
    Goust2 k(6,6);
    g=&h;
    g->put();
    g=&k;
    g->put();
    return 0;
}

同时,不希望一个类被继承也可以使用final。

C++中, 虚函数可以为private, 并且可以被子类覆盖(因为虚函数表的传递),但子类不能调用父类的private虚函数。虚函数的重载性和它声明的权限无关。


编译器不检查虚函数的各类属性。被virtual修饰的成员函数,不论他们是private、protect或是public的,都会被统一的放置到虚函数表中。对父类进行派生时,子类会继承到拥有相同偏移地址的虚函数表(相同偏移地址指,各虚函数相对于VPTR指针的偏移),则子类就会被允许对这些虚函数进行重载。且重载时可以给重载函数定义新的属性,例如public,其只标志着该重载函数在该子类中的访问属性为public,和父类的private属性没有任何关系!


纯虚函数可以设计成私有的,不过这样不允许在本类之外的非友元函数中直接调用它,子类中只有覆盖这种纯虚函数的义务,却没有调用它的权利。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值