0.目录

1.同名覆盖

2.赋值兼容

3.函数重写遇上赋值兼容

4.小结

1.同名覆盖

子类中是否可以定义父类中的同名成员?如果可以,如何区分?如果不可以,为什么?

父子间的冲突:

  • 子类可以定义父类中的同名成员
  • 子类中的成员将隐藏父类中的同名成员
  • 父类中的同名成员依然存在于子类中
  • 通过作用域分辨符( :: )访问父类中的同名成员

访问父类中的同名成员:

示例:

  1. #include <iostream>
  2. using namespace std;
  3. class Parent
  4. {
  5. public:
  6. int mi;
  7. Parent()
  8. {
  9. cout << "Parent() : " << "&mi = " << &mi << endl;
  10. }
  11. };
  12. class Child : public Parent
  13. {
  14. public:
  15. int mi;
  16. Child()
  17. {
  18. cout << "Child() : " << "&mi = " << &mi << endl;
  19. }
  20. };
  21. int main()
  22. {
  23. Child c;
  24. c.mi = 100;
  25. c.Parent::mi = 1000;
  26. cout << "&c.mi = " << &c.mi << endl;
  27. cout << "c.mi = " << c.mi << endl;
  28. cout << "&c.Parent::mi = " << &c.Parent::mi << endl;
  29. cout << "c.Parent::mi = " << c.Parent::mi << endl;
  30. return 0;
  31. }

运行结果为:

  1. [root@bogon Desktop]# g++ test.cpp
  2. [root@bogon Desktop]# ./a.out
  3. Parent() : &mi = 0x7ffe251260c0
  4. Child() : &mi = 0x7ffe251260c4
  5. &c.mi = 0x7ffe251260c4
  6. c.mi = 100
  7. &c.Parent::mi = 0x7ffe251260c0
  8. c.Parent::mi = 1000

类中的成员函数可以进行重载:

  1. 重载函数的本质为多个不同的函数
  2. 函数名参数列表是唯一的标识
  3. 函数重载必须发生在同一个作用域中

子类中定义的函数是否能重载父类中的同名函数?

示例:

  1. #include <iostream>
  2. using namespace std;
  3. class Parent
  4. {
  5. public:
  6. int mi;
  7. void add(int v)
  8. {
  9. mi += v;
  10. }
  11. void add(int a, int b)
  12. {
  13. mi += (a + b);
  14. }
  15. };
  16. class Child : public Parent
  17. {
  18. public:
  19. int mi;
  20. void add(int v)
  21. {
  22. mi += v;
  23. }
  24. void add(int a, int b)
  25. {
  26. mi += (a + b);
  27. }
  28. void add(int x, int y, int z)
  29. {
  30. mi += (x + y + z);
  31. }
  32. };
  33. int main()
  34. {
  35. Child c;
  36. c.mi = 100;
  37. c.Parent::mi = 1000;
  38. cout << "c.mi = " << c.mi << endl;
  39. cout << "c.Parent::mi = " << c.Parent::mi << endl;
  40. c.add(1);
  41. c.add(2, 3);
  42. c.add(4, 5, 6);
  43. cout << "c.mi = " << c.mi << endl;
  44. cout << "c.Parent::mi = " << c.Parent::mi << endl;
  45. return 0;
  46. }

运行结果为:

  1. [root@bogon Desktop]# g++ test.cpp
  2. [root@bogon Desktop]# ./a.out
  3. c.mi = 100
  4. c.Parent::mi = 1000
  5. c.mi = 121
  6. c.Parent::mi = 1000

父子间的冲突:

  • 子类中的函数将隐藏父类的同名函数
  • 子类无法重载父类中的成员函数
  • 使用作用域分辨符访问父类中的同名函数
  • 子类可以定义父类中完全相同的成员函数

示例:

  1. #include <iostream>
  2. using namespace std;
  3. class Parent
  4. {
  5. public:
  6. int mi;
  7. void add(int v)
  8. {
  9. mi += v;
  10. }
  11. void add(int a, int b)
  12. {
  13. mi += (a + b);
  14. }
  15. };
  16. class Child : public Parent
  17. {
  18. public:
  19. int mi;
  20. void add(int x, int y, int z)
  21. {
  22. mi += (x + y + z);
  23. }
  24. };
  25. int main()
  26. {
  27. Child c;
  28. c.mi = 100;
  29. c.Parent::mi = 1000;
  30. cout << "c.mi = " << c.mi << endl;
  31. cout << "c.Parent::mi = " << c.Parent::mi << endl;
  32. c.Parent::add(1);
  33. c.Parent::add(2, 3);
  34. c.add(4, 5, 6);
  35. cout << "c.mi = " << c.mi << endl;
  36. cout << "c.Parent::mi = " << c.Parent::mi << endl;
  37. return 0;
  38. }

运行结果为:

  1. [root@bogon Desktop]# g++ test.cpp
  2. [root@bogon Desktop]# ./a.out
  3. c.mi = 100
  4. c.Parent::mi = 1000
  5. c.mi = 115
  6. c.Parent::mi = 1006

2.赋值兼容

子类对象可以当作父类对象使用(兼容性):

  • 子类对象可以直接赋值给父类对象
  • 子类对象可以直接初始化父类对象
  • 父类指针可以直接指向子类对象
  • 父类引用可以直接引用子类对象

示例——能编译通过的赋值兼容:

  1. #include <iostream>
  2. using namespace std;
  3. class Parent
  4. {
  5. public:
  6. int mi;
  7. void add(int i)
  8. {
  9. mi += i;
  10. }
  11. void add(int a, int b)
  12. {
  13. mi += (a + b);
  14. }
  15. };
  16. class Child : public Parent
  17. {
  18. public:
  19. int mv;
  20. void add(int x, int y, int z)
  21. {
  22. mv += (x + y + z);
  23. }
  24. };
  25. int main()
  26. {
  27. Parent p;
  28. Child c;
  29. p = c; // 第1种兼容性
  30. Parent p1(c); // 第2种兼容性
  31. Parent& rp = c; // 第3种兼容性
  32. Parent* pp = &c; // 第4种兼容性
  33. rp.mi = 100;
  34. rp.add(5); // 没有发生同名覆盖?
  35. rp.add(10, 10); // 没有发生同名覆盖?
  36. return 0;
  37. }

当使用父类指针(引用)指向子类对象时:

  • 子类对象退化为父类对象
  • 只能访问父类中定义的成员
  • 可以直接访问被子类覆盖的同名成员

3.函数重写遇上赋值兼容

特殊的同名函数:

  • 子类中可以重定义父类中已经存在的成员函数
  • 这种重定义发生在继承中,叫做函数重写
  • 函数重写是同名覆盖的一种特殊情况

当函数重写遇上赋值兼容会发生什么?

示例——函数重写遇上赋值兼容:

  1. #include <iostream>
  2. using namespace std;
  3. class Parent
  4. {
  5. public:
  6. int mi;
  7. void add(int i)
  8. {
  9. mi += i;
  10. }
  11. void add(int a, int b)
  12. {
  13. mi += (a + b);
  14. }
  15. void print()
  16. {
  17. cout << "I'm Parent." << endl;
  18. }
  19. };
  20. class Child : public Parent
  21. {
  22. public:
  23. int mv;
  24. void add(int x, int y, int z)
  25. {
  26. mv += (x + y + z);
  27. }
  28. void print()
  29. {
  30. cout << "I'm Child." << endl;
  31. }
  32. };
  33. void how_to_print(Parent* p)
  34. {
  35. p->print();
  36. }
  37. int main()
  38. {
  39. Parent p;
  40. Child c;
  41. how_to_print(&p); // Expected to print: I'm Parent.
  42. how_to_print(&c); // Expected to print: I'm Child.
  43. return 0;
  44. }

运行结果为:

  1. [root@bogon Desktop]# g++ test.cpp
  2. [root@bogon Desktop]# ./a.out
  3. I'm Parent.
  4. I'm Parent.

问题分析:

  • 编译期间,编译器只能根据指针的类型判断所指向的对象
  • 根据赋值兼容,编译器认为父类指针指向的是父类对象
  • 因此,编译结果只可能是调用父类中定义的同名函数



在编译这个函数的时候,编译器不可能知道指针p究竟指向了什么。但是编译器没有理由报错。于是,编译器认为最安全的做法是调用父类的print函数,因为父类和子类肯定都有相同的print函数。

4.小结

  • 子类可以定义父类中的同名成员
  • 子类中的成员将隐藏父类中的同名成员
  • 子类和父类中的函数不能构成重载关系
  • 子类可以定义父类中完全相同的成员函数
  • 使用作用域分辨符访问父类中的同名成员
  • 子类对象可以当作父类对象使用(赋值兼容)
  • 父类指针可以正确的指向子类对象
  • 父类引用可以正确的代表子类对象
  • 子类中可以重写父类中的成员函数

C++解析(22):父子间的冲突的更多相关文章

  1. iframe兄弟间和iframe父子间的值传递问题

    在网上查了资料.iframe的参数传递问题.有很多答案都是不可行的.现在将收集的资料整理一下.已经验证通过.以下如有问题请及时指正. 1. iframe兄弟之间值传递 举例说明:index页面中有两个 ...

  2. vue2.0非父子间进行通讯

    在vue中,父组件向之组件通讯使用的是props,子组件向父组件通讯使用的是$emit+事件,那非父子间的通讯呢,在官方文档上只有寥寥数笔, 概念很模糊,这个空的vue实例应该放在哪里呢,光放文档并没 ...

  3. 父子间的通信,以及ref

    <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title&g ...

  4. vue组件父子间通信之综合练习--假的聊天室

    <!doctype html> <html> <head> <meta charset="UTF-8"> <title> ...

  5. Aangular 父子间组件传递

    1.父子间组件传递------重点&难点 Vue.js和Angular中的父子间消息传递原理一样,都可以用口诀: “Props Down,Events Up” 方向1:父 =>子 父组件 ...

  6. vue中父子间传值和非父子间传值

    vue传值一般分三种方式:父组件向子组件传值.子组件向父子间传值.非父子组件进行传值 一.父组件向子组件传值:父组件引用子组件后,通过数据绑定(v-bind)向子组件传值 父组件: <templ ...

  7. EventBus完全解析--组件/线程间通信利器

    github地址:https://github.com/greenrobot/EventBus 1, Android EventBus实战, 没听过你就out了 2,  Android EventBu ...

  8. vue 父子间组件传值

    1.父组件向子组件传值: 实例截图: 实例代码: /*子组件代码*/ //child.vue <template> <div style="border: 1px soli ...

  9. iOS 全屏侧滑/UIScrollView/UISlider间滑动冲突

    代码地址如下:http://www.demodashi.com/demo/13848.html 效果预览 一.前期准备 有一个支持全屏侧滑返回的视图控制器ViewController,ViewCont ...

随机推荐

  1. [arc076F]Exhausted?

    Description 传送门 Solution 额外的椅子可以放置在任意实数位置,所以该问题其实就问最多能够有多少人坐下.由于每个人的需求有<=l和>=r两个限制,并不是很好下手,我们先 ...

  2. day4 RHCE

    12.实现一个web服务器 [root@server0 ~]# yum install httpd -y [root@server0 ~]# rpm -ql httpd 查看httpd产生的配置文件 ...

  3. LVS入门篇(四)之LVS实战

    一.LVS的NAT模式实战 1.环境说明: HOST OS role remask 192.168.56.12 Centos 7.4 LVS调度器(1.2.7) VIP:192.168.0.104 1 ...

  4. 用phpcms如何将静态页面制作成企业网站(上)

    首先,先要准备好这个静态网页的源文件,如图 bs里面是一些css和js的文件,img则是放图片的,文件中的index是网页的首页 运行一下,看看 是这样的 然后打开phpcms文件,上篇博客中有提到, ...

  5. Android线程管理(一)——线程通信

    线程通信.ActivityThread及Thread类是理解Android线程管理的关键. 线程,作为CPU调度资源的基本单位,在Android等针对嵌入式设备的操作系统中,有着非常重要和基础的作用. ...

  6. C/C++ 下mysql应用封装(连接增删改查)

    mysql - 初始化 1) mysql_init():初始化数据库 2) mysql_real_connect()(不推荐用Mysql_connect()):连接数据库 详细代码如下: bool d ...

  7. Linux 安装Zookeeper<单机版>(使用Mac远程访问)

    阅读本文需要先阅读安装Zookeeper<准备> 新建目录 mkdir /usr/local/zookeeper 解压 cd zookeeper压缩包所在目录 tar -xvf zooke ...

  8. 百度地图之自动提示--autoComplete

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  9. Sublime Text 3高效实用快捷键

    2017-11-27 16:18:48 Sublime Text 3 高效实用快捷键 Sublime Text 3 软件及注册码 官网下载链接在这里,有时候会很神奇的上不去,可能是因为被Q了,可能就是 ...

  10. nginx原声方法按照每天日志切割保存

    首先配置日志变量,然后配置日志 在/etc/nginx/conf.d/default.conf 配置变量 server{ if ($time_iso8601 ~ "^(\d{4})-(\d{ ...