C++_virtual 关键字

一、简介

virtual 在英文中表示 “虚”、“虚拟” 的含义。
C++ 中的关键字 “virtual” 主要用在两个方面:虚函数虚基类

二、虚函数与虚基类

1. 虚函数

虚函数是多态的一种。
在C++中,基类的指针或引用可以指向或引用派生类对象。
派生类可以重写基类中的成员函数。

{
    class base
    {
        public:
        void test(){ cout << “基类方法”; }
    };
    
    class inheriter:public base
    {
        public:
        void test(){ cout << “派生类方法”; }
    };
}

可以在基类中将被重写的成员函数设置为虚函数,其含义是:“当通过基类的指针或引用调用该成员函数时,将根据指针指向的对象类型确定调用的函数,而非指针的类型。

{
	base* p1 = new base;
	base* p2 = new inheriter;
	p1->test();
	p2->test();
}

将test() 函数设置为vritual 后:

{
	base* p1 = new base;
	base* p2 = new inheriter;
	p1->test();
	p2->test();
}

如此,便可以将基类和派生类的同名方法区分开,实现多态。

说明:

一、只需将基类中的成员函数声明为虚函数即可,派生类中重写的virtual函数自动成为虚函数;
二、 基类中的析构函数必须为虚析构函数,否则会出现对象释放错误。以上例说明,如果不将其基类的析构函数声明为virtual,那么在调用delete p2;语句时将调用基类的析构函数,而不是应当调用的派生类的析构函数,从而出现对象释放错误的问题。
三、 虚函数的使用将导致类对象占用更大的内存空间。对这点的解释涉及到虚函数调用的原理:编译器给每一个包括虚函数的对象添加了一个隐藏成员:指向虚函数表的指针。
四、重写函数的特征标必须与基类函数一致,否则将覆盖基类函数。
2. 虚基类

在C++中,派生类可以继承多个基类。

  1. 问题在于:如果这多个基类又是继承同一个基类时,那么派生类是不是需要多次继承这“同一个基类”的内容?这时候虚基类的作用就发挥出来了。
  2. 虚基类可以使得继承同一个基类的派生类们的派生类对象只继承一个对象。
    虚继承写法:**
    class 派生类名:virtual [访问符] 基类名
  3. base称为mytest1类的虚基类。假设base还是另外一个类mytest2的虚基类,对于多重继承mytest1和mytest2的子类mytest3而言,base的部分只继承了一次。
class base
{
	public:
	int b;
	virtual void test(void)
	{ 
		std::cout << “base’s test”;
		return;
	}
	virtual ~base(){ };
};
class mytest1:virtual public base{ };
class mytest2:virtual public base{ };
class mytest3:public mytest1, public mytest2{ };
std::cout << sizeof(mytest1) << “\”;
std::cout << sizeof(mytest2) << “\”;
std::cout << sizeof(mytest3) << std::endl;;
//输出
//12\12\16

程序说明:

一、mytest1类与mytest2类的大小为什么是12?这是因为它们在虚继承base类后,添加了一个隐藏的成员—指向虚基类的指针,占?1 个字节,而base类本身占?2 个字节,因此它们的大小均为?3 ,而对非虚继承而言,是不需要这样的一个指针的。mytest3类的大小为:

sizeof(base) + sizeof(mytest1 - base) + siezeof(mytest2 - base),即?4 字节。

说明:

1. 若一个类多重继承自具有同一个基类的派生类时,调用同名成员函数时会出现二义性。为了解决这个问题。可以通过作用域解析运算符澄清,或者在类中进行重新定义。
2. 继承关系可能是非常繁复的。一个类可能的多重继承自别的类,而它的父类也可能继承自别的类。当该类从不同的途径继承了两个或者更多的同名函数时,如果没有对类名限定为virtual,将导致二义性。当然,如果使用了虚基类,则不一定会导致二义性。编译器将选择继承路径上“最短”的父类成员函数加以调用。该规则与成员函数的访问控制权限并不矛盾。也就是说,不能因为具有更高调用优先级的成员函数的访问控制权是“private”,而转而去调用public型的叫低优先级的同名成员函数。

  1. 32位主机为4字节,64位主机为8字节,不包括虚析构函数 ↩︎

  2. 32位主机为8字节,64位主机为16字节 ↩︎

  3. 32位主机为12字节,64位主机为24字节 ↩︎

  4. 32位主机为16字节,64位主机为32字节 ↩︎

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值