【C++基础之十八】类继承中的隐藏规则

原创 2013年12月10日 15:01:46

原创作品,转载请标明http://blog.csdn.net/jackystudio/article/details/17243251


记得以前看林锐博士的《高质量C++编程指南》一书有提到类继承中的隐藏问题,当时网上也有不同的声音,觉得并没有隐藏这个东西,后来在看C++ primer的时候确实有提到这个问题(谓之“屏蔽”),这里记下来,如果理解有误,还请指出。


1.重载和覆盖

在了解隐藏之前,得先分清楚重载和覆盖。

(1)重载:对同一个类而言的,函数名相同,函参不同,因为是在同一个类中,所以是否是virtual并不重要。

(2)覆盖:对基类和派生类而言。函数名相同,函参相同,必须是virtual函数。

如下示例,1和2是重载关系,而1和3是覆盖关系。

class A{
public:
	virtual void fun(){cout<<"A::fun()";}//1
	void fun(int a){cout<<"A::fun(a)";}//2
};

class B : public A{
public:
	void fun(){cout<<"B::fun()";}//3
};

2.隐藏

首先隐藏也是发生对基类和派生类而言的,所以主要就是要理清隐藏和覆盖的差异。

(1)如上所述,覆盖要求是virtual函数,所以如果是不带virtual的同名同参函数,那么就是隐藏。

(2)不管有没有virtual标识,函参不一样,那么也是隐藏。

如下示例,1和3同名同参,但是无virtual标识,所以是隐藏。2和4函参不同,所以也是隐藏。

class A{
public:
	void fun1(){cout<<"A::fun1()";}//1
	virtual void fun2(int a){cout<<"A::fun2(a)";}//2
};

class B : public A{
public:
	void fun1(){cout<<"B::fun1()";}//3
	void fun2(){cout<<"B::fun2()";}//4
};


3.一种简单区分调用方法

如果对上面的重载,覆盖,隐藏还是搞不清楚,再加上多态的使用,更会是云里雾里。这里提供了一种方便理解的区分调用方法(From C++ primer)。

(1)首先确定进行函数调用的对象、引用或指针的静态类型

(2)在该类中查找函数,如果找不到,就在直接基类中查找,如此循着类的继承链往上找,直到找到该函数或者查找完最后一个类。如果不能在类或其相关基类中找到该名

字,则调用是错误的

(3)一旦找到了该名字,就进行常规类型检查,查看如果给定找到的定义,该函数调用是否合法。

(4)假定函数调用合法,编译器就生成代码。如果函数是虚函数且通过引用或指针调用,则编译器生成代码以确定根据对象的动态类型运行哪个函数版本,否则,编译器生成

代码直接调用函数。


4.示例

class A{
public:
	virtual void fun1(){cout<<"A::fun1()";}//1
	void fun2(){cout<<"A::fun2()";}//2
	virtual void fun3(){cout<<"A::fun3()";}//3
};

class B : public A{
public:
	void fun1(){cout<<"B::fun1()";}//4
	void fun3(int a){cout<<"B::fun3(a)";}//5
};

int _tmain(int argc, _TCHAR* argv[])
{
	B b;
	b.fun1();
	b.fun2();
	b.fun3(1);

	A* pa=new B();
	pa->fun1();
	pa->fun2();
	pa->fun3();
}
按照上述方法分析:

(1)B b。B类型,所以所有的调用要先在B类中查找。

fun1存在,所以调用4。

fun2不存在,所以在基类A中查找,存在fun2(),所以调用2。

fun3存在,但是要求带参,所以只能调用fun3(int a),如果b.fun3()则会报错,因为一旦找到名字就会停下,进行类型匹配检查。所以调用5。

(2)A* pa=new B()。A类型指针,所以所有的调用要现在A类中查找(此时不会再到B中查找,但不意味着不调用B中函数

fun1存在,因为new的是B的对象,而且是虚函数,所以到B中查找是否进行了覆盖,发现确实进行了覆盖,所以调用4。

fun2存在,调用2。

fun3存在,因为new的是B的对象,而且是虚函数,所以到B中查找是否进行了覆盖,发现没有有进行覆盖,所以调用3。



版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

C++继承详解之二——派生类成员函数详解(函数隐藏、构造函数与兼容覆盖规则)

在这一篇文章开始之前,我先解决一个问题。 在上一篇C++继承详解之一——初探继承中,我提到了在派生类中可以定义一个与基类成员函数同名的函数,这样派生类中的函数就会覆盖掉基类的成员函数。 在谭浩强的C+...

c/c++基础(十八) #pragma pack

程序编译器对结构的存储的特殊处理确实提高CPU存储变量的速度,但是有时候也带来了一些麻烦,我们也屏蔽掉变量默认的对齐方式,自己可以设定变量的对齐方式。 编译器中提供了#pragma pack(n)来...

【Visual C++】游戏开发笔记十八 游戏基础物理建模(一) 匀速与加速运动

本系列文章由zhmxy555(毛星云)编写,转载请注明出处。 http://blog.csdn.net/zhmxy555/article/details/7496200作者:毛星云    邮箱: ha...
  • zhmxy555
  • zhmxy555
  • 2012年04月25日 04:06
  • 27488

C++程序员学Java系列之十八:继承和抽象

继承 关键字:extends 格式: class 子类 extends 父类 {} 在Java中,类的继承是指在一个现有类的基础上去构建一个新的类,构建出来的新类被称作子类,现有类被称作父类,子类...

C++ 父类与派生类关系 隐藏规则

作用域可见性:     如果存在两个或多个具有包含关系的作用域,外层声明了一个标识符,而内层没有再次声明同名标识符,那么外层标识符在内层依然可见,如果在内层声明了同名标识符,则外层标识符在内层不可见...

C++父类与子类关系以及函数重载、覆盖和隐藏规则

转自:http://blog.csdn.net/xingyu19871124/article/details/7640131 在C++语言中,虚函数是非常重要的概念,虚函数是实现C++面向对象中多态...
  • h_wlyfw
  • h_wlyfw
  • 2014年01月15日 17:40
  • 601

JAVA基础再回首(十八)——Map集合概述及成员方法、Map集合的三个子类、Collections类

JAVA基础再回首(十八)——Map集合概述及成员方法、Map集合的三个子类、Collections类 版权声明:转载必须注明本文转自程序员杜鹏程的博客:http://blog.csdn.net/...
  • m366917
  • m366917
  • 2016年08月22日 00:41
  • 1032

程序开发基础学习二(C++ Google Style 命名规则)

无规矩不成方圆,新的岗位就需要服从团队的编码规则。很开心团队用的是Google的C++编码规则,大概看了下Google 的编码规则,正如九天翔雁说的:“Google的 C++ Style Guide远...
  • hackmind
  • hackmind
  • 2011年07月15日 11:04
  • 11607

机器学习(十八)——关联规则挖掘

机器学习(十八)——关联规则挖掘

java并发编程(十八)--深入Java内存模型—内存操作规则总结

主内存与工作内存     Java内存模型的主要目标是定义程序中各个变量的访问规则,即在虚拟机中将变量存储到内存和从内存中取出变量这样的底层细节。此处的变量主要是指共享变量,存在竞争问题的变量。...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:【C++基础之十八】类继承中的隐藏规则
举报原因:
原因补充:

(最多只允许输入30个字)