共享遗产

几天前,我们发布了 两个C++测验 基于论坛上发布的问题。让我们复习第一个问题

null

测验1
  1. #包括
  2. 福{
  3. 公众的 :
  4. 事实上的 无效 DoStuff()=0;
  5. };
  6. 酒吧: 公众的 福{
  7. 公众的 :
  8. 事实上的 无效 多斯凝灰岩( 内景 a) =0;
  9. };
  10. 巴兹: 公众的 酒吧{
  11. 公众的 :
  12. 无效 多斯凝灰岩( 内景 (一) 覆盖
  13. {
  14. 标准::cout<< “Baz::DoStuff(int)” ;
  15. }
  16. 无效 多斯塔夫() 覆盖
  17. {
  18. 标准::cout<< “Baz::DoStuff()” ;
  19. }
  20. };
  21. 内景 主(){
  22. 巴兹巴兹;
  23. 巴*巴=&baz;
  24. pBar->DoStuff();
  25. }

这家伙很沮丧,因为他期待两件事:

  • 代码编译时不会出错。
  • 30号线最后会打电话来 Baz::DoStuff() 反过来,它会在输出控制台中打印相同的内容。

相反,他在同一行中得到了以下编译时错误

e:foo.cpp(30):错误C2660:’Bar::DoStuff’:函数不接受0个参数

这个编译错误的根源在第11行:因为我们正在关闭类的定义 酒吧 不提方法 多斯凝灰岩 没有论据,但是 多斯凝灰岩 在第10行中,有一个接受类型为的参数的版本 内景 ,我们只是把原稿藏起来 Foo::Stuff() 宣言。话虽如此,编译错误还是有道理的。

事实上 Foo::Stuff() 一个纯虚拟的方法根本不是发生这种情况的必要条件。虚拟方法和非虚拟方法也会发生这种情况。

我感觉到java和C语言开发人员在编码C++中的伪像时可能会遇到这种情况,因为在这些语言中,隐藏声明的概念是不可用的(有一种替代方法,包括声明成员为 私有的 ,因此子类不会使它们可见,但在这种情况下,隐藏内容的决定权属于超类的编码者。在C++中,决策是由派生类的编码器来进行的。

我的朋友如何克服这个错误以使应用程序按他所期望的那样工作?通过在Bar的定义中包含using声明,如第5行的声明:

  1. 酒吧: 公众的 福{
  2. 公众的 :
  3. //使用从基中引入名称
  4. //在派生类作用域中初始化。
  5. 使用 Foo::DoStuff;
  6. 事实上的 无效 多斯凝灰岩( 内景 a) =0;
  7. };

现在应用程序按最初的预期运行。

Quiz 1 running


在测验2中,我们刚刚回顾的C++原理也适用,但是如果隐藏不是我们想要做的,这个问题可能变成更危险的事情,因为应用程序无论如何都会编译,而在运行时必须发现不希望的行为。

测验2
  1. #包括
  2. 福{
  3. 公众的 :
  4. 事实上的 无效 多斯凝灰岩( 烧焦 a) =0;
  5. };
  6. 酒吧: 公众的 福{
  7. 公众的 :
  8. 事实上的 无效 多斯凝灰岩( 内景 a) =0;
  9. };
  10. 巴兹: 公众的 酒吧{
  11. 公众的 :
  12. 无效 多斯凝灰岩( 内景 (一) 覆盖
  13. {
  14. 标准::cout<< “Baz::DoStuff(int)” ;
  15. }
  16. 无效 多斯凝灰岩( 烧焦 (一) 覆盖
  17. {
  18. 标准::cout<< “Baz::DoStuff(字符)” ;
  19. }
  20. };
  21. 内景 主(){
  22. 巴兹巴兹;
  23. 巴*巴=&baz;
  24. pBar->DoStuff公司( “a” );
  25. }

尽管事实上 Foo::DoStuff(字符) 在第30行中不可见,作为参数接收的’a’隐式转换为 内景 类型,生产:

Implicit conversion

同样,这里的解决方案是基于前面的using声明:

  1. 酒吧: 公众的 福{
  2. 公众的 :
  3. 使用 Foo::DoStuff;
  4. 事实上的 无效 多斯凝灰岩( 内景 a) =0;
  5. };

一旦声明,我们只需编译,运行和…瞧à

Quiz 2 fixed

总之,隐藏基类方法既不是坏事,也不是要避免的事情,只要它正是您想要得到的。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享