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提供的基本语法基本可以满足一般性修改,但是对于把普通堆表改为分区表,把索引组织表修改为堆表等操作就 ...
随机推荐
- wordpress文章链接怎么把默认的别名改成id形式和伪静态设置
别名默认是文章标题,打不开,改成英文形式可以打开,但这样很不方便,还有可能重复.怎么改成按文章id自动生成相应链接呢 找到设置---固定链接----把默认的日期和名称型改成自定义结构把末尾的%post ...
- C++11 std::move和std::forward
下文先从C++11引入的几个规则,如引用折叠.右值引用的特殊类型推断规则.static_cast的扩展功能说起,然后通过例子解析std::move和std::forward的推导解析过程,说明std: ...
- filter的使用
(1)什么是filter 过滤器是处于客户端与服务器资源文件之间的一道过滤网,在访问资源文件之前,通过一系列的过滤器对请求进行修改,判断等,把不符合规则的请求在中途拦截或者修改.或者对响应进行过滤.拦 ...
- 第六周java学习总结
学号 20175206 <Java程序设计>第六周学习总结 教材学习内容总结 第七章: 主要内容 内部类 匿名类 异常类 断言 重点和难点 重点:内部类和异常类的理解 难点:异常类的使用 ...
- laravel安装nova 运行php artisan migrate出错
报错一$ php artisan migrate Illuminate\Database\QueryException : could not find driver (SQL: select * f ...
- js/vue图片压缩
js版 新建compressImage.js,内容如下: // 将base64转换为blob(有需要可加上,没需要可不加) function convertBase64UrlToBlob(urlDat ...
- CSS 分栏结构
CSS 固定左侧导航栏 left----左侧菜单 cont -- 实际内容 right ---右侧附加内容 两栏布局---左侧高度为内容撑开的高度 方法一:[坏处是需要 float] ...
- DUMP 5 企业级电商项目
[订单模块] 创建订单 商品信息 订单列表 订单详情 取消订单 订单列表 订单搜素 订单详情 订单发货 [创建订单] 购物车勾选商品 涉及 Cart Product => 一个商品 ...
- 【ARC 063F】Snuke's Coloring 2
Description There is a rectangle in the xy-plane, with its lower left corner at (0,0) and its upper ...
- Python中所有的关键字
在python中若想查询python中有哪些关键字可以先导入keyword模块 import keyword #导入关键字模块print(keyword.kwlist) #查询所有关键字 查询结果: ...