继承的相关知识
来源:互联网 发布:linux fm驱动 编辑:程序博客网 时间:2024/06/01 09:43
1. 继承的概念
- 定义:继承是面向对象复用的重要手段,即面向对象的可重用性是通过“继承”来实现的。解决在已有的类中增加新的特性,减少重复的工作量的问题。
- 已经存在的类,叫“基类”或“父类”;建立的新的类,叫“派生类”或“子类”。继承是类型之间的关系模型,共享公有的东西,实现类内各自不同的东西。
- 继承的定义格式为:
class DeriveLcassName(派生类):acess-label(继承类型)BaseClassName,其中冒号后面的统称为派生类列表。 - 继承的分类:
继承分为单继承和多继承。
(1) 单继承是一个派生类只从一个基类派生,称为单继承。
示意如下:
图中,箭头表示继承的方向,从派生类继承于基类。
下面是简单的单继承代码:
class Person{public: void Display() { cout<<_name<<endl; }protected: string _name; //姓名private: int _age;};class Student: public Person{protected: int _num; //学号};void Test(){ Person p; Student s; //1.子类给父类 p = s; //2.父类给子类 // s = p; //3.父类通过指针/引用给子类 Person *p1 = &s; //Person &p1 = s; //4. 子类的指针/引用不能指向父类对象(可以通过强制转换完成) Student *p2 = (Student *)&p; //Student &s = (Student &)p; //p2->_num = 10;//不可访问 //p2._num = 10;}
(2)多继承:是一个派生类有两个或多个基类,称为多重继承。
简单示意如下:
简单的对多继承的理解,代码如下:
class Person{public: friend void Display(Person &p,Student &s); void buy() //虚函数 { cout<<"买东西"<<endl; } protected: string _name;};class Student:public Person{public: //virtual// void display_1() { cout<<"买半价"<<endl; cout<<Person::_name<<endl; }protected : int _strNum; protected: //int _num;};void Display(Person &p,Student &s){ cout<<p._name<<endl; cout<<s._strNum<<endl;}void Fun(){ Person p; Student s; Display (p, s);}int main(){ Person p; Student s; //cout<<p._name<<endl; //Fun(s); return 0;}
2. 继承中的规则
- 继承关系中构造、析构函数调用顺序
(1)构造函数调用顺序
(2)析构函数调用顺序 - 继承与转换–赋值兼容规则
(1)子类对象可以全部赋值给父类;
(2)父类对象不能赋值给子类对象;
(3)父类的指针或引用可赋值给子类对象;
(4)子类对象的指针或引用不能赋值给父类对象,但可通过强制类型转换完成。
3. 菱形继承
菱形继承是由单继承和多继承组合的一种复杂的继承关系,存在二义性和数据冗余的问题。而菱形虚拟继承则是为了解决菱形继承所存在的问题。菱形继承的简单示意图如下:
其中派生类D既继承于C1,又继承于C2,通过派生类调用基类中的成员或成员函数时会产生二义性的问题
模型如下图:
简单模拟代码如下:
//菱形继承#include<iostream>using namespace std;class B{public: int _b; int _b1;};class c1:public B{public: int _c1; int _c;};class c2:public B{public: int _c2;};class D:public c1,public c2{public: int _d; int _d1;};int main(){ D d1; d1._d = 1; d1._d1 = 4;// d1._b1; //这里不能通过编译,现象对D::_b1访问不明确,出现模糊调用的情况 d1.B::_b1 = 3; //这里能通过编译,但仍会显示对基类“B”访问不明确 return 0;}
在对基类中的成员变量访问时,必须使用域访问限定符,否则编译器无法识别是哪个对象中的_b1赋值,虽然解决了二义性问题,但是产生了数据冗余.
为了解决菱形继承产生的二义性和数据冗余的问题,采用了菱形虚拟继承的方法,现对菱形虚拟继承概括:
4 菱形虚拟继承
- 定义:菱形虚拟继承是在继承类型前加入虚拟(virtual)关键字,且使用的是偏移量表格。
- 同名隐藏规则:
虚基类是只有一个拷贝;
作用分辨符(::)的访问方式:基类::成员(参数)/成员
同名隐藏规则:没有虚函数的情况下,派生类中新增的与基类中的函数同名的函数,即使参数个数不同,则基类中的同名函数被覆盖;如果派生类中的多个基类拥有同名成员函数,派生类也新增了同名函数,则基类都被隐藏(这种情况,对派生类的访问用对象名。成员名,对基类的用作用分辨符)。- 菱形虚拟继承关系:
继承关系如下图所示:
- 菱形虚拟继承关系:
菱形虚拟继承模型如下:
如图所示:
Address1,Address2这里均存的是指针,指针指向偏移量表格。偏移量表格中先存该派生类相对于自己的地址,后存该派生类相对于基类的地址。
代码及分析如下:
//菱形虚拟继承#include<iostream>using namespace std;class B{public: int _b; int _b1;};class C1:virtual public B{public: int _cc; int _c;};class C2:virtual public B{public: int _c2;};class D:public C1,public C2{public: int _d; int _d1;};void test(){ D d1; d1.C1::_b = 2; d1.C2::_b = 7; d1._b1 = 3; d1._d = 1; d1._d1 = 4;}int main(){ test(); return 0;}
在调试过程中,先看看d1中存了些什么:
能看出d1存储了指针变量的地址,指针变量的内容是指向虚基类的地址,是4个字节,然后再看看这个地址中存放了什么。
1c转换成十进制是28,32位平台下一个地址是4个字节,因此,指向的是继承关系的模型中的_d1
好了,基本的先总结到这里~
阅读全文
1 0
- 继承的相关知识
- 继承的相关知识
- C++的继承相关知识
- C++继承的相关知识
- C++继承相关知识
- Java中类的继承相关的知识
- 黑马程序员_面向对象中继承的相关知识
- 继承和构造器相关知识的个人理解
- java继承与接口相关知识
- 继承的相关知识以及多态的概念及理解
- 相关reactjs的相关知识
- C++ 类的相关知识 构造,析构,继承与多态
- C++中虚函数与纯虚函数以及虚继承的相关知识
- java基础第六天——继承以及抽象类相关的知识
- js对象、继承,原型链相关知识的复习及应用心得
- 继承的相关注意事项
- 继承 的 相关概念
- OPC的相关知识
- bzoj1924: [Sdoi2010]所驼门王的宝藏
- 华为笔试题1
- 2017暑假集训 div1 线段树(1)
- [bzoj3282]Tree Link-Cut-Tree
- 程序、任务、进程和线程的联系与区别
- 继承的相关知识
- 使用Java 8 的日期和时间Api
- spring AOP---【小白系列】0基础到熟练应用spring框架(三)
- 洛谷P1008 三连击
- hdu5701中位数计数(百度之星)
- 考试排名
- Java集合总结(二)
- 黑马商城项目(三)之一
- 伪类