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)作用域与重定义,赋值兼容规则的更多相关文章

  1. C++中的继承详解(3)作用域与重定义,赋值兼容规则

    作用域与同名隐藏 一样的,先上代码 1 class A 2 { 3 public: 4 int a_data; 5 void a() 6 { 7 cout << "A" ...

  2. C++中的继承(3)作用域与重定义,赋值兼容规则

    作用域与重定义(同名隐藏) 一样的,先上代码 1 class A 2 { 3 public: 4 int a_data; 5 void a() 6 { 7 cout << "A& ...

  3. C++语言笔记系列之十六——赋值兼容规则&amp;多继承的二义性

    1.赋值兼容规则 (1)派生类对象能够给基类对象赋值,这样的情况下派生类对象将从基类继承的成员的值赋值给一个基类对象:可是不同意将一个基类的对象赋值给一个派生类. (2)能够将派生类对象的地址赋给基类 ...

  4. c++ 公有继承的赋值兼容规则

    赋值兼容规则是指在需要基类对象的任何地方都可以使用公有派生类的对象来替代.通过公有继承,派生类得到了基类中除构造函数.析构函数之外的所有成员,而且所有成员的访问控制属性也和基类完全相同.这样,公有派生 ...

  5. C++学习笔记 封装 继承 多态 重写 重载 重定义

    C++ 三大特性 封装,继承,多态 封装 定义:封装就是将抽象得到的数据和行为相结合,形成一个有机的整体,也就是将数据与操作数据的源代码进行有机的结合,形成类,其中数据和函数都是类的成员,目的在于将对 ...

  6. VC中链接错误,提示string重定义

    VC链接错误,说是string已经有了实现了,只要 rebuild 一下好了. Linking...LINK : warning LNK4075: ignoring '/EDITANDCONTINUE ...

  7. 初步学习C++中的继承关系

    继承机制是面向对象程序设计使代码能够复用的最重要的手段,它同意程序猿在保持原有类特性的基础上进行扩展,添加功能. 这样产生新的类,称派生类.继承呈现了面向对象程序设计的层次结构,体现了由简单到复杂 ...

  8. python的父类和子类中关于继承的不同版本的写法

    Python 2.7中的继承 在Python 2.7中,继承语法稍有不同,ElectricCar 类的定义类似于下面这样: class Car(object): def __init__(self, ...

  9. oracle在线重定义表

    在一个高可用系统中,如果需要改变一个表的定义是一件比较棘手的问题,尤其是对于7×24系统.Oracle提供的基本语法基本可以满足一般性修改,但是对于把普通堆表改为分区表,把索引组织表修改为堆表等操作就 ...

随机推荐

  1. Spark-1(概念)

    1. 什么是Spark? Apache Spark™是用于大规模数据处理的统一分析引擎. spark是一个实现快速通用的集群计算平台.它是由加州大学伯克利分校AMP实验室开发的通用内存并行计算框架,用 ...

  2. 【LOJ#3096】[SNOI2019]数论

    [LOJ#3096][SNOI2019]数论 题面 LOJ 题解 考虑枚举一个\(A\),然后考虑有多少个合法的\(B\). 首先这个数可以写成\(a_i+kP\)的形式,那么它模\(Q\)的值成环. ...

  3. GWAS群体分层校正,该选用多少个PCA

    前言 关于选用多少个PCA做群体分层校正,各大期刊并没有一个统一的说法. 故做了如下综述. 1 随心所欲型,想选多少就选多少 PCA想选多少就选多少,这个真的不是开玩笑.有文献出处有真相! 比如下面文 ...

  4. pandas的读写

    import as pd import numpy as np import matplotlib.pyplot as plt #df.to_excel('C:Users/history/Deskto ...

  5. Hibernate日志输出到SLF4J

    一,Hibernate日志问题 工程使用SLF4J,但日志文件一直没有看到Hibernate相关日志及showsql 二,Logback文件配置 修改Hibernate 日志输出指定为SLF4J,当修 ...

  6. web 框架

    一个实际的案例介绍Spring Boot + Vue 前后端分离 https://www.cnblogs.com/nele/p/7858581.html#_caption_7 https://www. ...

  7. JGUI源码:组件及函数封装方法(7)

    以Accordion为例1.在base.js定义一个对象,这样可以和JQuery对象区分开,用户使用组件时比较清晰一点,也可以在这里引用多个库. var JGUI = J = { version : ...

  8. 使用antd Table + mobx 处理数组 出现的一系列问题

    在store中定义了一个数组: @observable list = [...] 若是在table组件中直接使用list: <Table className={styles.table} col ...

  9. shell 批量修改较长字符串 字符串内容之间更换位置

    cat 1.txt src='http://img2.tgbusdata.cn/v2/thumb/jpg/MkY5Myw2NTUsMzAzLDksMywxLC0xLDAscms1MCwxOTIuMTY ...

  10. C# Datetime时间指定时区

    string start_time_str = "2018-03-21 06:00:00"; DateTime.Parse(start_time_str) // :: 格林威治时间 ...