C++ 避免隐藏继承而来的名称
来源:互联网 发布:mac看不了群相册 编辑:程序博客网 时间:2024/06/07 14:24
关于C++中继承这个概念相比大家都很熟悉,那么子类究竟能从父类继承到哪些东西,哪些东西又是子类继承不到的呢?可能很多人都会觉得父类所有的东西都会被子类继承,包括成员函数和成员变量,否则就违背了“父子关系”这字面上的意思,其实不然,首先我们先看一小段简单的代码,这段代码很容易理解
仔细看主函数里面的注释,这段代码几乎会让很多人第一次看到都很诧异
首先普及两点常识,大虾略过
1. 重载这个概念很重要,这是C++比C多出来的功能,我们知道C是不支持函数重载的,这也是限制C开发大型程序的原因之一。
重载发生在同一个类中(父类和子类不叫同一类,虽然可以称他们为同一类型)
函数名称相同,参数不同
函数重载忽略返回值和virtual关键字(如果仅仅是返回值不同或有无virtual关键字的区别,不算函数重载)
下面是对函数重载为什么忽略返回值的解释:
void Function(void);
int Function (void);
上述两个函数,第一个没有返回值,第二个的返回值是int 类型。如果这样调用函数:
int x = Function ();
则可以判断出Function 是第二个函数。问题是在C++/C 程序中,我们可以忽略函数的返回值。在这种情况下,编译器和程序员都不知道哪个Function 函数被调用。
所以只能靠参数而不能靠返回值类型的不同来区分重载函数。编译器根据参数为每个重载函数产生不同的内部标识符
2. 隐藏这个概念
隐藏就是“内部作用域”的名称隐藏"外部作用域“的名称,例如局部变量会隐藏同名的全局变量,同样, 子类的名称会隐藏父类的名称。这篇文章主要解释的就是关于继承中存在的隐藏的问题
好了,有了上面的知识,我们就可以对上面的代码加以分析了。Base类中的fun1和fun2函数都被重载了,我们在主函数中调用fun1()函数是没有问题的,因为在Derived类中存在这个函数,这里我们调用的fun1()就是Derived类中的fun1()。再往后面看,我们调用fun1(8)函数会出现错误,在Base类中明明存在virtual void fun1(int)这个函数,我们又使用了public继承,为什么这里调用会出错呢?难道是没有继承到fun1(int)这个函数,是不是很奇怪?这是因为子类中存在fun1()函数,编译器在子类中找到fun1()这个符号,就不会再去父类里查找fun1(int),虽然父类里面有我们需要的函数。但是编译器不管,只要找到fun1()这个符号,它就再往下查找。这就导致了父类中所有与子类同名的函数都将被隐藏,而这肯定与我们绝大多数时候的意愿是相违背的。
C++这么做是有原因的,记住一句话,C++每一种行为的背后都有其深层的原理,搞清楚这背后的原理对我们理解C++很有帮助。
关于这种行为背后原理的权威解释,在《Effetive C++》中有这么一段话:
”这些行为背后的原理是为了防止你在程序库或应用框架内建立新的derived class时从疏远的的base classes继承重载函数“。
仔细分析下这句话C++这么做确实有道理的,如果程序规模比较大,类继承层次比较深时,如果C++没有这种隐藏特性,那么子类中的重载函数数量就会非常多,这样就增加了我们调用这些函数出错的可能性。但是很多情况下我们不需要编译器这样”弄巧成拙“,那么如何解决这个问题,也就是让编译器不要隐藏域子类同名的函数。显然C++是给出了解决办法的,我们可以使用using声明来解决这个问题。看下面的代码
通过在Derived类中引入using申明,我们将Base类中的所有fun1,fun2, fun3函数添加进了子类,这样子类对象在调用这些函数时就没有任何问题了。
所以当我们继承父类,而且父类存在重载函数,我们又在子类重新定义了这些重载函数的一部分,那么我们必须为那些原本会被隐藏的名称加上using申明,否则那些我们希望继承的名称会被隐藏掉而又不给我们任何提示。
现在让我们再深入一点,如果我们不希望继承所有父类中的成员函数(这里与今天的主题并不矛盾),这在public继承中是不可能的,也是没有意义的。在public继承中父类和子类关系式is-a。然后这在private继承中是有意义的,这么说吧,假设我们只想继承Base类中带参数的fun2版本,即void fun2(int)这个函数。上面提到的using声明显然已经不足以解决这个问题,因为using声明会将父类中所有指定
名称的函数都在子类中可见,所以需要另外的解决办法,看代码:
在这段代码中,将Base类中的fun2(int)函数放在Derived类中的CallBaseFun2(int x)函数中实现调用,而Base中的无参数fun2版本void fun2()不能调用。好了,关于C++中继承和隐藏的类容就差不多了。
总结:
Derived类中的名称会隐藏Base类中同名的名称,在public继承中我们可以通过引入using声明,在private继承中我们可以通过一个转接函数来解决这个问题。
参考文献:
1. 《Effective C++》
点击(此处)折叠或打开
- #include <iostream>
- using namespace std;
- class Base
- {
- public:
- virtual void fun1() = 0;
- virtual void fun1(int)
- {
- }
- virtual void fun2()
- {
- }
- void fun2(int)
- {
- }
- void fun3(float)
- {
- }
- };
- class Derived:public Base
- {
- public:
- virtual void fun1()
- {
- }
- void fun3()
- {
- }
- void fun4()
- {
- }
- };
- int main()
- {
- Derived a;
- a.fun1(); //correct Derived:fun1();
- //a.fun1(8); //incorrect
- a.fun2(); //correct Base:fun2()
- a.fun2(3); //correct Base:fun2(int);
- a.fun3(); //correct Derived:fun3()
- //a.fun3(3.0); //incorrect
- cout << "Hello world!" << endl;
- return 0;
- }
首先普及两点常识,大虾略过
1. 重载这个概念很重要,这是C++比C多出来的功能,我们知道C是不支持函数重载的,这也是限制C开发大型程序的原因之一。
重载发生在同一个类中(父类和子类不叫同一类,虽然可以称他们为同一类型)
函数名称相同,参数不同
函数重载忽略返回值和virtual关键字(如果仅仅是返回值不同或有无virtual关键字的区别,不算函数重载)
下面是对函数重载为什么忽略返回值的解释:
void Function(void);
int Function (void);
上述两个函数,第一个没有返回值,第二个的返回值是int 类型。如果这样调用函数:
int x = Function ();
则可以判断出Function 是第二个函数。问题是在C++/C 程序中,我们可以忽略函数的返回值。在这种情况下,编译器和程序员都不知道哪个Function 函数被调用。
所以只能靠参数而不能靠返回值类型的不同来区分重载函数。编译器根据参数为每个重载函数产生不同的内部标识符
2. 隐藏这个概念
隐藏就是“内部作用域”的名称隐藏"外部作用域“的名称,例如局部变量会隐藏同名的全局变量,同样, 子类的名称会隐藏父类的名称。这篇文章主要解释的就是关于继承中存在的隐藏的问题
好了,有了上面的知识,我们就可以对上面的代码加以分析了。Base类中的fun1和fun2函数都被重载了,我们在主函数中调用fun1()函数是没有问题的,因为在Derived类中存在这个函数,这里我们调用的fun1()就是Derived类中的fun1()。再往后面看,我们调用fun1(8)函数会出现错误,在Base类中明明存在virtual void fun1(int)这个函数,我们又使用了public继承,为什么这里调用会出错呢?难道是没有继承到fun1(int)这个函数,是不是很奇怪?这是因为子类中存在fun1()函数,编译器在子类中找到fun1()这个符号,就不会再去父类里查找fun1(int),虽然父类里面有我们需要的函数。但是编译器不管,只要找到fun1()这个符号,它就再往下查找。这就导致了父类中所有与子类同名的函数都将被隐藏,而这肯定与我们绝大多数时候的意愿是相违背的。
C++这么做是有原因的,记住一句话,C++每一种行为的背后都有其深层的原理,搞清楚这背后的原理对我们理解C++很有帮助。
关于这种行为背后原理的权威解释,在《Effetive C++》中有这么一段话:
”这些行为背后的原理是为了防止你在程序库或应用框架内建立新的derived class时从疏远的的base classes继承重载函数“。
仔细分析下这句话C++这么做确实有道理的,如果程序规模比较大,类继承层次比较深时,如果C++没有这种隐藏特性,那么子类中的重载函数数量就会非常多,这样就增加了我们调用这些函数出错的可能性。但是很多情况下我们不需要编译器这样”弄巧成拙“,那么如何解决这个问题,也就是让编译器不要隐藏域子类同名的函数。显然C++是给出了解决办法的,我们可以使用using声明来解决这个问题。看下面的代码
点击(此处)折叠或打开
- #include <iostream>
- using namespace std;
- class Base
- {
- public:
- virtual void fun1() = 0;
- virtual void fun1(int)
- {
- }
- virtual void fun2()
- {
- }
- void fun2(int)
- {
- }
- void fun3(float)
- {
- }
- };
- class Derived:public Base
- {
- public:
- using Base::fun1;
- using Base::fun2;
- using Base::fun3;
- virtual void fun1()
- {
- }
- void fun3()
- {
- }
- void fun4()
- {
- }
- };
- int main()
- {
- Derived a;
- a.fun1(); //correct Derived:fun1();
- a.fun1(8);
- a.fun2(); //correct Base:fun2()
- a.fun2(3); //correct Base:fun2(int);
- a.fun3(); //correct Derived:fun3()
- a.fun3(3.0);
- cout << "Hello world!" << endl;
- return 0;
- }
所以当我们继承父类,而且父类存在重载函数,我们又在子类重新定义了这些重载函数的一部分,那么我们必须为那些原本会被隐藏的名称加上using申明,否则那些我们希望继承的名称会被隐藏掉而又不给我们任何提示。
现在让我们再深入一点,如果我们不希望继承所有父类中的成员函数(这里与今天的主题并不矛盾),这在public继承中是不可能的,也是没有意义的。在public继承中父类和子类关系式is-a。然后这在private继承中是有意义的,这么说吧,假设我们只想继承Base类中带参数的fun2版本,即void fun2(int)这个函数。上面提到的using声明显然已经不足以解决这个问题,因为using声明会将父类中所有指定
名称的函数都在子类中可见,所以需要另外的解决办法,看代码:
点击(此处)折叠或打开
- #include <iostream>
- using namespace std;
- class Base
- {
- public:
- virtual void fun1() = 0;
- virtual void fun1(int)
- {
- }
- virtual void fun2()
- {
- }
- void fun2(int)
- {
- }
- void fun3(float)
- {
- }
- };
- class Derived:private Base
- {
- public:
- virtual void fun1()
- {
- cout<<"This function is implemented to avoid to be a abstract class";
- }
- void CallBaseFun2(int x)
- {
- Base::fun2(x);
- }
- };
- int main()
- {
- Derived a;
- CallBaseFun2(3);
- //a.fun2(); //incorrect
- cout << "Hello world!" << endl;
- return 0;
- }
总结:
Derived类中的名称会隐藏Base类中同名的名称,在public继承中我们可以通过引入using声明,在private继承中我们可以通过一个转接函数来解决这个问题。
参考文献:
1. 《Effective C++》
0
上一篇:VLC播放RTSP视频延迟问题
下一篇:Linux中的内存管理
相关热门文章
- mount命令
- 三亚六天五晚甜蜜旅行...
- 撰写页面标题优化的7个技巧...
- 小心二手车骗子
- 网络服务提供者对反通...
- test123
- 编写安全代码——小心有符号数...
- 使用openssl api进行加密解密...
- 一段自己打印自己的c程序...
- sql relay的c++接口
- socket编程开启混杂模式的目的...
- C++ 嵌套类是干什么的?...
- C++ 单例怎么写?
- sizeof 这个操作符都有什么特...
- Oracle VM server 如何删除vm ...
给主人留下些什么吧!~~
评论热议
0 0
- C++ 避免隐藏继承而来的名称
- C++ 避免隐藏继承而来的名称
- 避免遮掩继承而来的名称
- 避免遮掩继承而来的名称
- 避免掩蔽继承而来的名称
- 避免遮掩继承而来的名称
- 继承:避免遮掩继承而来的名称
- 《Effective C++》读书笔记之item33:避免遮掩继承而来的名称
- 《Effective C++》学习笔记条款33 避免遮掩继承而来的名称
- Effective C++:条款33:避免遮掩继承而来的名称
- 避免遮掩继承而来的名称(Effective C++_33)
- 读书笔记《Effective C++》条款33:避免遮掩继承而来的名称
- C++之避免遮掩继承而来的名称(33)---《Effective C++》
- [effectiv c++]条款33:避免遮掩继承而来的名称(重载,重写,重定义)
- 条款33:避免遮掩继承而来的名称
- 条款33:避免遮掩继承而来的名称
- 条款33:避免遮掩继承而来的名称
- 条款33:避免遮掩继承而来的名称
- C++中-如何跟踪函数和类
- Linux下编译VLC for Android源代码总结
- Mac OS上编译Mobile VLC for ios
- MySQL 下载及使用
- VLC播放RTSP视频延迟问题
- C++ 避免隐藏继承而来的名称
- Linux中的内存管理
- 关于C++中虚函数表存放位置的思考
- 利用QT和libvlc写RTSP播放器
- Malloc最多一次能分配多少内存
- C++中关于全局对象的初始化顺序
- 删除/var/log/messages文件的恢复方法
- 网络编程
- 如何判断Javascript对象是否存在
原创粉丝点击
热门IT博客
热门问题
老师的惩罚
人脸识别
我在镇武司摸鱼那些年
重生之率土为王
我在大康的咸鱼生活
盘龙之生命进化
天生仙种
凡人之先天五行
春回大明朝
姑娘不必设防,我是瞎子
突然头疼是什么原因
缓解头疼的方法
头疼是什么引起的
为什么经常头疼
经期头疼是什么原因
早晨起来头疼怎么回事
经常头疼怎么回事啊
经常性头疼是怎么回事
每天头疼是怎么回事
恶心头疼怎么回事
老头疼是怎么回事
神经性头疼怎么缓解
一低头就头疼
头晕头疼怎么回事
每天下午头疼
一到晚上就头疼
早上起床头疼
头疼吃什么食物好
喝多头疼怎么办
例假头疼是什么原因
头疼恶心怎么办
睡觉起来头疼
后脑勺头疼的原因
为什么老是头疼
头疼浑身没劲
头疼什么原因
怎样缓解头疼
头疼吃什么好
经常头疼是什么原因引起的
感冒头疼怎么缓解
为什么总是头疼
头疼怎样缓解
头疼是什么病
偏头疼怎么回事
我头疼怎么办
为什么总头疼
得了偏头疼怎么办
总头疼怎么回事
头疼是怎么回事
睡不好觉头疼怎么办
头疼看哪个科