虚函数的继承与作用域分析

继承中的作用域

派生类的作用域镶嵌在基类的作用域里面,类似于

{
    Base scope
    ...
    {
         Derived Class scope
         ....
    }
}

那么,编译器在进行Name Lookup的时候,内部的作用域会隐藏外部具有相同名字的函数或变量。

隐藏与Override的区别

在理解虚函数在继承中与作用域的关系的时候,正确区分隐藏与override至关重要。

  • 隐藏代表外层作用域中的同名函数或变量依旧存在,但是默认情况下访问的是内层作用域中的函数或变量。为了使用外层作用域的函数或变量,需要使用作用域运算符::
  • override代表原来的函数已经不复存在,被另一个同名字的函数所替代。这也是为什么通过指针或引用访问虚函数的时候会出现多态现象的原因。

举个栗子

// virtualScope.h
#pragma once
#include <iostream>
class Base {
public:
	virtual void fcn() { std::cout << "Base::fcn() ---- virtual" << std::endl; }
};

class D1 : public Base {
public:
	// 隐藏了Base类中的虚函数fcn()
	// D1继承了Base::fcn()的定义
	// 此处的fcn(int)不是虚函数
	// 此处的参数列表与Base中的虚函数fcn不同
	void fcn(int x) { std::cout << "D1::fcn(int x) ---- non-virtual" << " x = " << x << std::endl; } 
	// 新的虚函数,在Base类中不存在
	virtual void f2() { std::cout << "D1::f2() ---- virtual" << std::endl; };
};

class D2 : public D1 {
public:
	void fcn() { std::cout << "D2::fcn() ---- override Base::fcn()" << std::endl; }
	void fcn(int x) { std::cout << "D2::fcn(int x) ---- non-virtual, hides D2::fcn(int x)" << std::endl; }
	void f2() { std::cout << "D2::f2() ---- virtual, override D2::fcn()" << std::endl; }
};

// main.cpp
#include <iostream>
#include "virtualScope.h"

int main()
{
	Base bobj;
	D1 d1obj;
	D2 d2obj;
	Base *bptr1 = &bobj, *bptr2 = &d1obj, *bptr3 = &d2obj;
	D1 *d1ptr2 = &d1obj, *d1ptr3 = &d2obj;
	D2 *d2ptr3 = &d2obj;
	bptr1->fcn(); // virtual call, will call Base::fcn() at run time
	bptr2->fcn(); // virtual call, will call Base::fcn() at run time
	bptr3->fcn(); // virtual call, will call D2::fcn() at run time
	// bptr2->f2(); // error: Base ha no member named f2
	d1ptr2->f2(); // virtual call, will call D1::f2() at run time
	// d1ptr2->fcn(); // error: more parameter needed
	d1ptr2->fcn(2); // normal call, will call D1::fcn(int) at compile time
	d1ptr3->f2(); // virtual call, will call D2::f2() at run time
	// d1ptr3->fcn(); // error: more parameter needed
	d1ptr3->fcn(3); // statically bound, calls D1::fcn(int)
	d2ptr3->f2(); // virtual call, will call D2::f2() at run time
	d2ptr3->fcn(); // virtual call, will call D2::fcn() at run time
	d2ptr3->fcn(4); // statically bound, calls D2::fcn()
	return 0;
}

 

在Visual Studio 2015中的执行结果是

Base::fcn() ---- virtual
Base::fcn() ---- virtual
D2::fcn() ---- override Base::fcn()
D1::f2() ---- virtual
D1::fcn(int x) ---- non-virtual x = 2
D2::f2() ---- virtual, override D2::fcn()
D1::fcn(int x) ---- non-virtual x = 3
D2::f2() ---- virtual, override D2::fcn()
D2::fcn() ---- override Base::fcn()
D2::fcn(int x) ---- non-virtual, hides D2::fcn(int x)

 

发表评论

电子邮件地址不会被公开。 必填项已用*标注

13 − 11 =

98 − = 91