C++解析(22):父子间的冲突
0.目录
1.同名覆盖
2.赋值兼容
3.函数重写遇上赋值兼容
4.小结
1.同名覆盖
子类中是否可以定义父类中的同名成员?如果可以,如何区分?如果不可以,为什么?
父子间的冲突:
- 子类可以定义父类中的同名成员
- 子类中的成员将隐藏父类中的同名成员
- 父类中的同名成员依然存在于子类中
- 通过作用域分辨符( :: )访问父类中的同名成员
访问父类中的同名成员:
示例:
#include <iostream>
using namespace std;
class Parent
{
public:
int mi;
Parent()
{
cout << "Parent() : " << "&mi = " << &mi << endl;
}
};
class Child : public Parent
{
public:
int mi;
Child()
{
cout << "Child() : " << "&mi = " << &mi << endl;
}
};
int main()
{
Child c;
c.mi = 100;
c.Parent::mi = 1000;
cout << "&c.mi = " << &c.mi << endl;
cout << "c.mi = " << c.mi << endl;
cout << "&c.Parent::mi = " << &c.Parent::mi << endl;
cout << "c.Parent::mi = " << c.Parent::mi << endl;
return 0;
}
运行结果为:
[root@bogon Desktop]# g++ test.cpp
[root@bogon Desktop]# ./a.out
Parent() : &mi = 0x7ffe251260c0
Child() : &mi = 0x7ffe251260c4
&c.mi = 0x7ffe251260c4
c.mi = 100
&c.Parent::mi = 0x7ffe251260c0
c.Parent::mi = 1000
类中的成员函数可以进行重载:
- 重载函数的本质为多个不同的函数
- 函数名和参数列表是唯一的标识
- 函数重载必须发生在同一个作用域中
子类中定义的函数是否能重载父类中的同名函数?
示例:
#include <iostream>
using namespace std;
class Parent
{
public:
int mi;
void add(int v)
{
mi += v;
}
void add(int a, int b)
{
mi += (a + b);
}
};
class Child : public Parent
{
public:
int mi;
void add(int v)
{
mi += v;
}
void add(int a, int b)
{
mi += (a + b);
}
void add(int x, int y, int z)
{
mi += (x + y + z);
}
};
int main()
{
Child c;
c.mi = 100;
c.Parent::mi = 1000;
cout << "c.mi = " << c.mi << endl;
cout << "c.Parent::mi = " << c.Parent::mi << endl;
c.add(1);
c.add(2, 3);
c.add(4, 5, 6);
cout << "c.mi = " << c.mi << endl;
cout << "c.Parent::mi = " << c.Parent::mi << endl;
return 0;
}
运行结果为:
[root@bogon Desktop]# g++ test.cpp
[root@bogon Desktop]# ./a.out
c.mi = 100
c.Parent::mi = 1000
c.mi = 121
c.Parent::mi = 1000
父子间的冲突:
- 子类中的函数将隐藏父类的同名函数
- 子类无法重载父类中的成员函数
- 使用作用域分辨符访问父类中的同名函数
- 子类可以定义父类中完全相同的成员函数
示例:
#include <iostream>
using namespace std;
class Parent
{
public:
int mi;
void add(int v)
{
mi += v;
}
void add(int a, int b)
{
mi += (a + b);
}
};
class Child : public Parent
{
public:
int mi;
void add(int x, int y, int z)
{
mi += (x + y + z);
}
};
int main()
{
Child c;
c.mi = 100;
c.Parent::mi = 1000;
cout << "c.mi = " << c.mi << endl;
cout << "c.Parent::mi = " << c.Parent::mi << endl;
c.Parent::add(1);
c.Parent::add(2, 3);
c.add(4, 5, 6);
cout << "c.mi = " << c.mi << endl;
cout << "c.Parent::mi = " << c.Parent::mi << endl;
return 0;
}
运行结果为:
[root@bogon Desktop]# g++ test.cpp
[root@bogon Desktop]# ./a.out
c.mi = 100
c.Parent::mi = 1000
c.mi = 115
c.Parent::mi = 1006
2.赋值兼容
子类对象可以当作父类对象使用(兼容性):
- 子类对象可以直接赋值给父类对象
- 子类对象可以直接初始化父类对象
- 父类指针可以直接指向子类对象
- 父类引用可以直接引用子类对象
示例——能编译通过的赋值兼容:
#include <iostream>
using namespace std;
class Parent
{
public:
int mi;
void add(int i)
{
mi += i;
}
void add(int a, int b)
{
mi += (a + b);
}
};
class Child : public Parent
{
public:
int mv;
void add(int x, int y, int z)
{
mv += (x + y + z);
}
};
int main()
{
Parent p;
Child c;
p = c; // 第1种兼容性
Parent p1(c); // 第2种兼容性
Parent& rp = c; // 第3种兼容性
Parent* pp = &c; // 第4种兼容性
rp.mi = 100;
rp.add(5); // 没有发生同名覆盖?
rp.add(10, 10); // 没有发生同名覆盖?
return 0;
}
当使用父类指针(引用)指向子类对象时:
- 子类对象退化为父类对象
- 只能访问父类中定义的成员
- 可以直接访问被子类覆盖的同名成员
3.函数重写遇上赋值兼容
特殊的同名函数:
- 子类中可以重定义父类中已经存在的成员函数
- 这种重定义发生在继承中,叫做函数重写
- 函数重写是同名覆盖的一种特殊情况
当函数重写遇上赋值兼容会发生什么?
示例——函数重写遇上赋值兼容:
#include <iostream>
using namespace std;
class Parent
{
public:
int mi;
void add(int i)
{
mi += i;
}
void add(int a, int b)
{
mi += (a + b);
}
void print()
{
cout << "I'm Parent." << endl;
}
};
class Child : public Parent
{
public:
int mv;
void add(int x, int y, int z)
{
mv += (x + y + z);
}
void print()
{
cout << "I'm Child." << endl;
}
};
void how_to_print(Parent* p)
{
p->print();
}
int main()
{
Parent p;
Child c;
how_to_print(&p); // Expected to print: I'm Parent.
how_to_print(&c); // Expected to print: I'm Child.
return 0;
}
运行结果为:
[root@bogon Desktop]# g++ test.cpp
[root@bogon Desktop]# ./a.out
I'm Parent.
I'm Parent.
问题分析:
- 编译期间,编译器只能根据指针的类型判断所指向的对象
- 根据赋值兼容,编译器认为父类指针指向的是父类对象
- 因此,编译结果只可能是调用父类中定义的同名函数
在编译这个函数的时候,编译器不可能知道指针p究竟指向了什么。但是编译器没有理由报错。于是,编译器认为最安全的做法是调用父类的print函数,因为父类和子类肯定都有相同的print函数。
4.小结
- 子类可以定义父类中的同名成员
- 子类中的成员将隐藏父类中的同名成员
- 子类和父类中的函数不能构成重载关系
- 子类可以定义父类中完全相同的成员函数
- 使用作用域分辨符访问父类中的同名成员
- 子类对象可以当作父类对象使用(赋值兼容)
- 父类指针可以正确的指向子类对象
- 父类引用可以正确的代表子类对象
- 子类中可以重写父类中的成员函数
C++解析(22):父子间的冲突的更多相关文章
- iframe兄弟间和iframe父子间的值传递问题
在网上查了资料.iframe的参数传递问题.有很多答案都是不可行的.现在将收集的资料整理一下.已经验证通过.以下如有问题请及时指正. 1. iframe兄弟之间值传递 举例说明:index页面中有两个 ...
- vue2.0非父子间进行通讯
在vue中,父组件向之组件通讯使用的是props,子组件向父组件通讯使用的是$emit+事件,那非父子间的通讯呢,在官方文档上只有寥寥数笔, 概念很模糊,这个空的vue实例应该放在哪里呢,光放文档并没 ...
- 父子间的通信,以及ref
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title&g ...
- vue组件父子间通信之综合练习--假的聊天室
<!doctype html> <html> <head> <meta charset="UTF-8"> <title> ...
- Aangular 父子间组件传递
1.父子间组件传递------重点&难点 Vue.js和Angular中的父子间消息传递原理一样,都可以用口诀: “Props Down,Events Up” 方向1:父 =>子 父组件 ...
- vue中父子间传值和非父子间传值
vue传值一般分三种方式:父组件向子组件传值.子组件向父子间传值.非父子组件进行传值 一.父组件向子组件传值:父组件引用子组件后,通过数据绑定(v-bind)向子组件传值 父组件: <templ ...
- EventBus完全解析--组件/线程间通信利器
github地址:https://github.com/greenrobot/EventBus 1, Android EventBus实战, 没听过你就out了 2, Android EventBu ...
- vue 父子间组件传值
1.父组件向子组件传值: 实例截图: 实例代码: /*子组件代码*/ //child.vue <template> <div style="border: 1px soli ...
- iOS 全屏侧滑/UIScrollView/UISlider间滑动冲突
代码地址如下:http://www.demodashi.com/demo/13848.html 效果预览 一.前期准备 有一个支持全屏侧滑返回的视图控制器ViewController,ViewCont ...
随机推荐
- 1563: [NOI2009]诗人小G
1563: [NOI2009]诗人小G https://lydsy.com/JudgeOnline/problem.php?id=1563 分析: 直接转移f[i]=f[j]+cost(i,j),co ...
- Drupal views中实现两列布局
Views中的format有table,grid,unformatted list等,但是没有2 columns等选项. 如果要达到如下效果: 左侧一列有title,content,右侧一列image ...
- hdu2187悼念512汶川大地震遇难同胞——老人是真饿了(贪心 简单题)
传送门 简单题 #include<bits/stdc++.h> using namespace std; struct node { double dan,weight; }a[]; bo ...
- 【转】RobotFrameWork+APPIUM实现对安卓APK的自动化测试----第二篇【原理】
接着上一篇,我们开始聊聊APPIUM的框架和运行模式.废话不多说直接上图. 1.首先自动化脚本通过RobotFrameWork将命令传递给Appium的客户端: 2.然后[Appium的客户端]将接受 ...
- C语言--指针详解
这段时间在看 Linux 内核,深觉 C 语言功底不扎实,很多代码都看不太懂,深入学习巩固 C 语言的知识很有必要.先从指针开始. 一.什么是指针 C语言里,变量存放在内存中,而内存其实就是一组有序字 ...
- spring-boot Jpa配置
spring.jpa.hibernate.ddl-auto ddl-auto:create----每次运行该程序,没有表格会新建表格,表内有数据会清空 ddl-auto:create-drop---- ...
- React Native 【学习总结】-【常用命令】
前言 刚接触RN,相信很多人无从下手,不知道下一步要干什么,能干什么,本次学习围绕这个问题,将RN的常用命令总结一下,帮助你快速上手 架构理解 光知道命令的作用,远远不够,如果知道命令背后的意义,才能 ...
- Macbook Pro开机黑屏了。
问题描述:点了appstore的更新,然后重启黑屏.(说明:黑屏是屏幕没亮:灰屏是屏幕亮了是灰黑色的.) 黑屏问题大,灰屏问题小. 开机按option没反应的跳到步骤四 一.数据 苹果电脑黑屏了,想搞 ...
- 一个整数N中的1的个数
设计思想: 通过大量数据分解找规律 abcd 从d开始若d=0则count(1的个数)=左边的abc *d的位值(1.10.100..) 若等欲1则count=左边的abc*d的位值(1.10.100 ...
- ext4.1入门
ExtJS简介 Ext是一个Ajax框架,用于在客户端创建丰富多彩的web应用程序界面,是在Yahoo!UI的基础上发展而来的.官方网址:www.sencha.com ExtJS是一个用来开发前端应用 ...