virtual与override的区别

两者都是用于派生类重写基类的方法,其中virtual主要是在运行阶段实现多态,override主要是用在编译阶段语法检查。

一、virtual实现多态(重写)

1. 在使用基类指针时,调用的方法如果是virtual函数,子类只要重写,不管是否声明为virtual,都可以实现多态。

class QTestBase {
public:
	void testFunc() {
		qDebug() << "Test --- QTestBase::testFunc";
	}
};
class QTestChild : public QTestBase {
public:
	void testFunc() {
		qDebug() << "Test --- QTestChild::testFunc";
	}
};
class QTestChildEx : public QTestChild {
public:
	void testFunc() {
		qDebug() << "Test --- QTestChildEx::testFunc";
	}
};

定义test方法,验证上述结果:

void Test()
{
	QTestBase *pTest = new QTestChildEx();
	pTest->testFunc();
}

// Debug输出:Test --- QTestBase::testFunc

指针为QTestBase*类型,实际实例化的是QTestChildEx对象。testFunc()在QTestBase类中被定义为普通成员函数,即使子类重写了该方法,通过指针调用的仍然是QTestBase的方法。

2. 将QTestBase类中的testFunc()方法定义为虚函数。

class QTestBase {
public:
	virtual void testFunc() {
		qDebug() << "Test --- QTestBase::testFunc";
	}
};

即使QTestChild类和QTestChildEx类在重写testFunc()方法时,都未声明成virtual,但在实际应用中,基类指针调用testFunc()时,仍视为虚函数,实现多态效果。

Debug的输出结果:Test --- QTestChildEx::testFunc。

3. 如果指针被定义为QTestChild*,虽然QTestChild类中重写了testFunc()方法,且声明时并未加上virtual,但是仍能实现多态。

void Test()
{
	QTestChild *pTest = new QTestChildEx();
	pTest->testFunc();
}

// Debug结果:Test --- QTestChildEx::testFunc

总结:只要基类中的方法被声明为虚拟函数(virtual)了,基于其派生的子类,在重写此方法时,不管是否声明为virtual,都可以实现多态。

如果基类该方法未声明为虚函数,而是中间的子类重写函数声明了virtual,以中间子类为始,其后的派生类,该方法都视为虚函数。

4. 将基类QTestBase中的testFunction()方法定义为普通函数,而在QTestChild类中将该方法声明为虚函数。

class QTestBase {
public:
	void testFunc() {
		qDebug() << "Test --- QTestBase::testFunc";
	}
};
class QTestChild : public QTestBase {
public:
	virtual void testFunc() {
		qDebug() << "Test --- QTestChild::testFunc";
	}
};
class QTestChildEx : public QTestChild {
public:
	void testFunc() {
		qDebug() << "Test --- QTestChildEx::testFunc";
	}
};
class QTestChildEx2 : public QTestChildEx {
public:
	void testFunc() {
		qDebug() << "Test --- QTestChildEx2::testFunc";
	}
};

通过三种基类指针,测试结果如下: 

void Test()
{
	QTestBase *pTest = new QTestChildEx2();
	pTest->testFunc();
}
// Debug输出结果:Test --- QTestBase::testFunc

void Test()
{
	QTestChild *pTest = new QTestChildEx2();
	pTest->testFunc();
}
// Debug输出结果:Test --- QTestChildEx2::testFunc

void Test()
{
	QTestChildEx *pTest = new QTestChildEx2();
	pTest->testFunc();
}
// Debug输出结果:Test --- QTestChildEx2::testFunc

二、override(重写)

若使用override显式的说明重写某个函数,必须满足以下几个条件:

1、基类中必须已经声明了该方法,且必须声明为virtual方法,函数名、形参类型、常量属性 (constness) 和 引用限定符;

2、基类和派生类中,成员函数的返回类型和异常规格必须兼容。

编译错误情况一(基类未声明,子类定义override方法),如下所示:

class QTestBase {
public:
	void testFunc() {
		qDebug() << "Test --- QTestBase::testFunc";
	}
};
class QTestChild : public QTestBase {
public:
	virtual  void testFunc() {
		qDebug() << "Test --- QTestChild::testFunc";
	}
	void testFunc2() override {
		qDebug() << "Test --- QTestChild::testFunc2";
	}
};

// 编译时报错:error C3668: “QTestChild::testFunc2”: 包含重写说明符“override”的方法没有重写任何基类方法 (编译源文件 QTestChild.cpp)

编译错误情况二(基类已声明,但不是virtual方法,子类定义override方法),如下所示:

class QTestBase {
public:
	void testFunc() {
		qDebug() << "Test --- QTestBase::testFunc";
	}
	void testFunc2() {
		qDebug() << "Test --- QTestBase::testFunc2";
	}
};
class QTestChild : public QTestBase {
public:
	virtual  void testFunc() {
		qDebug() << "Test --- QTestChild::testFunc";
	}
	void testFunc2() override {
		qDebug() << "Test --- QTestChild::testFunc2";
	}
};

// 编译时报错:error C3668: “QTestChild::testFunc2”: 包含重写说明符“override”的方法没有重写任何基类方法 (编译源文件 QTestChildEx.cpp)

对于子类重写父类的方法上添加override,不影响类的多态特性。 override只是在编译阶段进行语法检查,提前找出错误。

在子类中virtual和override可以同时存在,即使不加virtual也不影响多态。

class QTestBase {
public:
	void testFunc() {
		qDebug() << "Test --- QTestBase::testFunc";
	}
	void testFunc2() { // 未声明virtual,若通过QTestBase *指针,调用testFunc2不能实现多态
		qDebug() << "Test --- QTestBase::testFunc2";
	}
};
class QTestChild : public QTestBase {
public:
	virtual  void testFunc() {
		qDebug() << "Test --- QTestChild::testFunc";
	}
	virtual void testFunc2() { // 已声明virtual
		qDebug() << "Test --- QTestChild::testFunc2";
	}
};
class QTestChildEx : public QTestChild {
public:
	void testFunc() {
		qDebug() << "Test --- QTestChildEx::testFunc";
	}
    // 未重写此方法
};
class QTestChildEx2 : public QTestChildEx {
public:
	void testFunc() {
		qDebug() << "Test --- QTestChildEx2::testFunc";
	}
	virtual void testFunc2() override { // virtual 和 override 关键字同时存在
		qDebug() << "Test --- QTestChildEx2::testFunc2";
	}
};

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在 C# 中,virtualoverride 都是关键字,用于实现面向对象编程中的多态性。 首先,virtual 关键字用于定义一个虚拟方法,即可以被子类重写的方法。使用 virtual 关键字标记的方法可以在父类中被定义,但是在子类中也可以被重新实现。 例如: ``` public class Animal { public virtual void Speak() { Console.WriteLine("I am an animal."); } } public class Dog : Animal { public override void Speak() { Console.WriteLine("I am a dog."); } } ``` 在上面的代码中,Animal 类中的 Speak() 方法被标记为 virtual,因此它可以在 Dog 类中被重写。在 Dog 类中,我们使用 override 关键字来重写 Speak() 方法。 在运行时,如果我们创建一个 Dog 实例并调用 Speak() 方法,将输出“我是一只狗”。 ``` Dog myDog = new Dog(); myDog.Speak(); // 输出 "I am a dog." ``` 注意:只有 virtual 方法才能被重写。 另一方面,override 关键字用于在子类中重写父类中已经定义的虚拟方法。重写方法必须与基类中定义的虚拟方法具有相同的名称、返回类型和参数列表。 例如,在上面的代码中,Dog 类重写了 Animal 类中的 Speak() 方法,并使用 override 关键字来标记它。这意味着在 Dog 类中,Speak() 方法将覆盖 Animal 类中的 Speak() 方法。 总之,virtualoverride 关键字都是用于实现多态性的重要工具,它们可以帮助我们在面向对象编程中更好地管理代码。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值