C++中的继承(3)作用域与重定义,赋值兼容规则
1、作用域与重定义(同名隐藏)
一样的,先上代码
1 class A
2 {
3 public:
4 int a_data;
5 void a()
6 {
7 cout << "A" << endl;
8 }
9 };
10 class B
11 {
12 public:
13 int b_data;
14 void b()
15 {
16 cout << "B" << endl;
17 }
18 };
19 class C :public A, public B
20 {
21 public:
22 int c_data;
23 void a(int data)//重载A类中的a()函数
24 {
25 cout << "C" << endl;
26 }
27 };
28 int main()
29 {
30 C c;
31 c.a();
32 return 0;
33 }
编译后,编译器会报错

错误表明:编译器并没有将c.a()看做C类继承自A类的a()函数,而是报错没有给a函数参数,即不构成函数重载,如果给c.a(10)一个参数,编译通过。输出:C
那么我们不给C类中定义同名函数呢
1 class A
2 {
3 public:
4 int a_data;
5 void a()
6 {
7 cout << "A" << endl;
8 }
9 };
10 class B
11 {
12 public:
13 int _data;
14 void b()
15 {
16 cout << "B" << endl;
17 }
18 };
19 class C :public A, public B
20 {
21 public:
22 int _data;
23 //void a(int data)
24 //{
25 // cout << "C" << endl;
26 //}
27 };
28 int main()
29 {
30 C c;
31 c.a();
32 return 0;
33 }
编译通过,运行输出:A
如果C类定义不传参的同名函数更能说明情况:
class C :public A, public B
{
public:
int _data;
void a()
{
cout << "C" << endl;
}
};
int main()
{
C c;
c.a();
getchar();
return ;
}
编译通过,运行输出:C
通过以上的例子,完全可以说明,当我们在派生类中定义一个同名函数的时候,编译器是将同名函数隐藏了,不管参数表是否相同。即不会构成函数重载,直接将基类函数覆盖。
那么问题来了,为什么不会构成函数重载呢?
一定要注意,函数重载的条件是在同一个作用域中才会构成函数重载,而派生类和基类是两个类域,一定不会构成函数重载的。
当然,我们还有另外一个方法访问同名时基类中的成员即
1 int main()
2 {
3 C c;
4 c._data;
5 c.B::_data;
6 c.a();
7 c.A::a();
8 getchar();
9 return 0;
10 }
B类的成员变量_data与C类中的成员变量_data也构成同名隐藏。
1. 在继承体系中基类和派生类是两个不同作用域。
2. 子类和父类中有同名 成员 , 子类成员 将屏蔽父类对成员 的直接访问。 ( 在子类成员 函数中, 可以 使用 基类: : 基类成员 访问) --隐藏 --重定义
3. 注意在实际中在继承体系里面最好不要定义同名 的成员 。
2、继承与转换——赋值兼容规则(public继承为例)
派生类和基类之间的特殊关系为:
1.派生类对象可以赋值给基类对象 ;基类对象不能赋值给派生类。
2.基类指针可以在不进行显示类型转换的情况下指向派生类对象 。
3.基类引用可以在不进行显示类型转换的情况下引用派生类对象,但是基类指针或引用只能用于调用基类的方法,不能用基类指针或引用调用派生类的成员及方法。
void FunTest(const Base&d)
{}
void FunTest1(const Derive&d)
{}
int main()
{
Derive d;
Base b();
b = d;//可以
d = b;//不行,访问的时候会越界
//上面已经解释过了
FunTest(b);
FunTest(d);
FunTest1(b); //报错
FunTest1(d);
Base* pBase = &d; //父类指针/或引用可以直接指向子类对象,但只能访问子类中继承父类的部分
Derive* pD = &b;//报错 子类的指针/引用不能直接指向父类对象
//如果非要这么做只能通过强制类型转换
Derive* pD = (Derive*)&b;//如果访问越界,程序会崩溃
}
通常,C++要求引用和指针类型与赋给的类型匹配,但这一规则对继承来说是个例外。但是这个例外是单向的,即仅仅不可以将基类对象和地址赋给派生类引用和指针。如果允许基类引用隐式的引用派生类对象,则可以使用基类引用为派生类对象调用基类的方法,因为派生类继承了基类的方法,所以这样不会出现问题。但是如果可以将基类对象赋给派生类引用,那么派生类引用能够为积累对象调用派生类方法,这样做会出现问题,例如:用基类对象调用派生类中新增的方法,是没有意义的,因为基类对象中根本没有派生类的新增方法。
3、友元与继承
class Person
{
friend void Display(Person &p, Student&s);
protected:
string _name; // 姓名
};
class Student : public Person
{
protected :
int _stuNum; // 学号
};
void Display(Person &p, Student &s)
{
cout << p._name << endl;
cout << s._name << endl;
cout << s._stuNum << endl;
}
void TestPerson1()
{
Person p;
Student s;
Display(p, s);
}

友元关系不能继承, 也就是说基类友元不能访问子类私有和保护成员 。友元只是能访问指定类的私有和保护成员的自定义函数,不是被指定类的成员,自然不能继承。
使用友元类时应该注意:
(1) 友元关系不能被继承。
(2) 友元关系是单向的,不具有交换性。若类B是类A的友元,类A不一定是类B的友元,要看在类中是否有相应的声明。
(3)友元关系不具有传递性。若类B是类A的友元,类C是B的友元,类C不一定是类A的友元,同样要看类中是否有相应的申明
(4)友元可以访问类的私有成员。
(5)友元只能出现在类定义内部,友元声明可以在类中的任何地方,一般放在类定义的开始或结尾。
(6)友元可以是普通的非成员函数,或前面定义的其他类的成员函数,或整个类。
(7)类必须将重载函数集中每一个希望设为友元的函数都声明为友元。
(8)友元关系不能继承,基类的友元对派生类的成员没有特殊的访问权限。如果基类被授予友元关系,则只有基类具有特殊的访问权限。该基类的派生类不能访问授予友元关系的类。
4、继承与静态成员
了解这个问题之前,我们先确定一件事情,那就是,在基类和派生类中,静态成员和静态成员函数共用同一段空间。 我们在以前的学习过程中都知道,类的模型是所有对象的数据成员单独存储,但是所有成员函数和静态成员是共用一段空间的
class Person
{
public :
Person() {++ _count; }
protected :
string _name ; // 姓名
public :
static int _count; // 统计人的个数。
} ;
int Person: : _count = ;
class Student : public Person
{
protected :
int _stuNum ; // 学号
} ;
class Graduate : public Student
{
protected:
string _seminarCourse; // 研究科目
} ;
void TestPerson1()
{
Student s1;
Student s2;
Student s3;
Graduate s4;
cout<<"人数: "<<Person: : _count<<endl;
Student : : _count = ;
cout<<"人数: "<<Person: : _count<<endl;
}
基类定义了 static成员 , 则整个继承体系里面只 有一个这样的成员 。 无论派生出多少个子类, 都只有 一个static成员 实例。父类的static变量和函数在派生类中依然可用,但是受访问性控制(比如,父类的private域中的就不可访问)。而且对static变量来说,派生类和父类中的static变量是共用空间的,这点在利用static变量进行引用计数的时候要特别注意。派生类的friend函数可以访问派生类本身的一切变量,包括从父类继承下来的protected域中的变量。但是对父类来说,他并不是friend的。
C++中的继承(3)作用域与重定义,赋值兼容规则的更多相关文章
- C++中的继承详解(3)作用域与重定义,赋值兼容规则
作用域与同名隐藏 一样的,先上代码 1 class A 2 { 3 public: 4 int a_data; 5 void a() 6 { 7 cout << "A" ...
- C++中的继承(3)作用域与重定义,赋值兼容规则
作用域与重定义(同名隐藏) 一样的,先上代码 1 class A 2 { 3 public: 4 int a_data; 5 void a() 6 { 7 cout << "A& ...
- C++语言笔记系列之十六——赋值兼容规则&多继承的二义性
1.赋值兼容规则 (1)派生类对象能够给基类对象赋值,这样的情况下派生类对象将从基类继承的成员的值赋值给一个基类对象:可是不同意将一个基类的对象赋值给一个派生类. (2)能够将派生类对象的地址赋给基类 ...
- c++ 公有继承的赋值兼容规则
赋值兼容规则是指在需要基类对象的任何地方都可以使用公有派生类的对象来替代.通过公有继承,派生类得到了基类中除构造函数.析构函数之外的所有成员,而且所有成员的访问控制属性也和基类完全相同.这样,公有派生 ...
- C++学习笔记 封装 继承 多态 重写 重载 重定义
C++ 三大特性 封装,继承,多态 封装 定义:封装就是将抽象得到的数据和行为相结合,形成一个有机的整体,也就是将数据与操作数据的源代码进行有机的结合,形成类,其中数据和函数都是类的成员,目的在于将对 ...
- VC中链接错误,提示string重定义
VC链接错误,说是string已经有了实现了,只要 rebuild 一下好了. Linking...LINK : warning LNK4075: ignoring '/EDITANDCONTINUE ...
- 初步学习C++中的继承关系
继承机制是面向对象程序设计使代码能够复用的最重要的手段,它同意程序猿在保持原有类特性的基础上进行扩展,添加功能. 这样产生新的类,称派生类.继承呈现了面向对象程序设计的层次结构,体现了由简单到复杂 ...
- python的父类和子类中关于继承的不同版本的写法
Python 2.7中的继承 在Python 2.7中,继承语法稍有不同,ElectricCar 类的定义类似于下面这样: class Car(object): def __init__(self, ...
- oracle在线重定义表
在一个高可用系统中,如果需要改变一个表的定义是一件比较棘手的问题,尤其是对于7×24系统.Oracle提供的基本语法基本可以满足一般性修改,但是对于把普通堆表改为分区表,把索引组织表修改为堆表等操作就 ...
随机推荐
- [oracle]解决ora-01034 oracle not available
一般都是数据库连接中断了,按照链接重连即可. https://jingyan.baidu.com/article/5552ef47c73eef518ffbc908.html
- 洛谷P3268 [JLOI2016]圆的异或并(扫描线)
扫描线还不是很熟啊--不管是从想的方面还是代码实现的方面-- 关于这题,考虑一条平行于\(y\)轴的扫描线从左到右扫描每一个圆,因为只有相离和内含两种关系,只用在切线处扫描即可 我们设上半圆为1,下半 ...
- Linux-进程管理
关于进程 Process what is process ? 什么是进程 process life cycle 进程的生命周期 process states 进程状态 什么是进程? 进程是已启动的可执 ...
- Python基础学习笔记4-28(持续更新)
Python学习笔记 第一章 计算机基础 1.1 硬件 计算机基本的硬件由:CPU / 内存 / 主板 / 硬盘 / 网卡 / 显卡 等组成,只有硬件但硬件之间无法进行交流和通信.需要操作系统进行协调 ...
- css控制table间距
border-collapse: separate;border-spacing: 20px 30px; /* 水平间距 垂直间距 */
- echarts 折线图自定义颜色与修改legend颜色
option4 = { title : { text: '', subtext: '' }, color:['#2db7f5','#ff6600','#808bc6'], //关键加上这句话 ...
- SQL Server 中字段的精度问题
在工作中遇到,一个多表联合查询的情况,查询出来的有些字段精度太高,小数点后达到8个0,现在客户要求报表只要精确到0.01 ,就是只要小数点后面只要保存两位,另外还需要四舍五入 在网上找了点资料,自己测 ...
- 【转载】Nginx + Tomcat 实现反向代理
通常的代理服务器,只用于代理内部网络对Internet的连接请求,客户机必须指定代理服务器,并将本来要直接发送到Web服务器上的http请求发送到代理服务器中由代理服务器向Internet上的web服 ...
- Apache Hadoop 2.9.2 的Federation架构设计
Apache Hadoop 2.9.2 的Federation架构设计 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 能看到这篇文件,说明你对NameNode的工作原理想必已经了如 ...
- Tomcat系列(6)——Tomcat处理一个HTTP请求的过程
Tomcat的架构图 图三:Tomcat Server处理一个HTTP请求的过程 处理HTTP请求过程 假设来自客户的请求为:http://localhost:8080/test/index.js ...