一,类继承

        定义:从已有的类派生出新的类,而派生类继承了原有类的特征,包括方法。

        目标:提供可重用的代码

二,一个简单的基类

#include <iostream> #include <cstring> using namespace std; class student      //基类 { private: char name[20]; int num; int age; public: student(const char *m_name,const int m_num,const int m_age); ~student(); virtual void display();//派生类有重载 故采用虚函数形式 }; class graduate:public student  //派生类    注意写法 { private: char major[20]; int thesis; public: graduate(const char *m_major,const int m_thesis,student &st); ~graduate(); void display(); void setThesis(int i);   }; student::student(const char *m_name,const int m_num,const int m_age) { strcpy(name,m_name); num=m_num; age=m_age; } student::~student() { cout<<"student is over"<<endl; } void student::display() { cout<<"name:"<<name<<"\nnum:"<<num<<"\nage"<<age<<endl; } graduate::graduate(const char* m_major, const int m_thesis, student& st):student(st) { //特别注意:由于派生类不能直接使用基类私有成员,所以必须使用基类构造函数 st.display(); strcpy(major,m_major); thesis=m_thesis; } graduate::~graduate() { cout<<"graduate is over"<<endl; } void graduate::display() { cout<<"major:"<<major<<"\nthesis:"<<thesis<<endl; } void graduate::setThesis(int i) { thesis=i; } int main() { student st("tianshuai",1,18); st.display(); cout<<"**************\n"; graduate gd("compuater",5,st); gd.display(); return 0; } 输出:name:tianshuai num:1 age18 ************** name:tianshuai num:1 age18 major:compuater thesis:5 graduate is over student is over student is over

【简介】1)继承类 继承了基类的私有成员,但是不能通过继承类的对象直接访问私有成员

               2)派生类不能直接访问基类私有成员,派生类构造函数必须使用基类构造函数

               3)派生类构造函数特点:基类对象首先被创建  创建graduate   gd(); student 对象先被创建

                                                           创建派生类对象时,先调用基类构造函数,再调用派生类构造函数

                                                            派生类对象过期时,先析构派生类,再析构基类

              4)不能讲基类对象和地址赋给派生类 

                        student st;

                        graduate  &gd=st;  //  Not  Allow

                        graduate  *gd=st;   //  Not  Allow

                    如果允许的话,则基类可以访问派生类成员,但访问基类没有的成员,对于基类对象来说是没有意义的

                        st.setThesis(int i)   //因为基类没有该方法

三,继承----- is-a 关系

        继承方式:共有继承、私有继承、保护继承

        共有继承建立一种is-a关系:派生类对象也是一个基类对象,可以对基类对象执行的任何操作,也可以对派生类对象执行

        例如:Fruit 是水果类,有重量和热量。Banana是派生类,包含重量和热量外,还添加专门香蕉成员,这些成员通常不用于Fruit.

四,多态共有继承

        两种实现机制:1>在派生类中重新定义基类方法。2>使用虚方法

        不存在虚拟构造函数,但基类的虚拟析构函数是必要的。请看下例:class ClxBase{ public: ClxBase(){cout << "Output from the con ClxBase!" << endl;}; virtual ~ClxBase(){cout << "Output from the destructor of class ClxBase!" << endl;}; virtual void DoSomething(){ cout << "Do something in class ClxBase!" << endl; }; }; class ClxDerived : public ClxBase{ public: ClxDerived() {cout << "Output from the con ClxDerived!" << endl;}; ~ClxDerived() { cout << "Output from the destructor of class ClxDerived!" << endl; }; void DoSomething() { cout << "Do something in class ClxDerived!" << endl; }; }; void main() { ClxBase *pTest = new ClxDerived; //基类的指针 引用派生类对象 pTest->DoSomething(); //调用派生类的方法 delete pTest; }输出:Do something in class ClxDerived!
           Output from the destructor of class ClxDerived!
这个很简单,非常好理解。
但是,如果把类ClxBase析构函数前的virtual去掉,那输出结果就是下面的样子了:
           Do something in class ClxDerived!
    也就是说,类ClxDerived的析构函数根本没有被调用!一般情况下类的析构函数里面都是释放内存资源,而析构函数不被调用的话就会造成内存泄漏。我想所有的C++程序员都知道这样的危险性。当然,如果在析构函数中做了其他工作的话,那你的所有努力也都是白费力气。
    当然,并不是要把所有类的析构函数都写成虚函数。因为当类里面有虚函数的时候,编译器会给类添加一个虚函数表,里面来存放虚函数指针,这样就会增加类的存储空间。所以,只有当一个类被用来作为基类的时候,才把析构函数写成虚函数。

五,静态联编和动态联编

        函数名联编:将源代码中函数调用解释为执行特定的函数代码块

        但是在C++中由于函数重载,编译器必须查看函数参数以及函数名才能确定使用哪个函数

        静态联编:在编译过程中进行联编

        但是虚函数使这项工作变得更困难,使用哪一个函数不能在编译时确定

        动态联编:程序运行时选择正确虚方法的代码

        1)为什么有两种类型联编,为什么 静态联编为默认

              动态联编让您能够重新定义类方法,而静态联编则很差,但静态联编效率高。

              如果派生类不重新定义基类任何方法,则不需要动态联编。仅仅将那些派生类需要重新定义的函数定义为虚拟的

        2)虚函数工作原理

              编译器给每个对象添加一个隐藏成员,其中保存一个该函数地址的指针,这种数组成为虚函数表。

              调用虚函数时,查看存储在对象中虚拟函数表地址,然后转向相应函数地址表,如果使用类声明中定义的第一个虚函数,则程序将使用数组中的第一个函数地址,并执行具有该地址的函数。

       3)注意事项

              如果重新定义继承的方法,则应确保与原来的原型完全相同。

              如果基类声明被重载了,则应在派生类中重新定义所有基类版本

六,抽象基类ABC(abstract base class)

        说明:某几个子类的所公有的数据和方法抽象出来组成一个抽象基类,然后从抽象基类中派生出这几个子类,可以通过基类指针数组同时管理这几个子类。对于每个子类中的不同方法,可以将该方法在抽象基类中定义为纯虚函数的方式,同时在各子类中将该方法定义为虚函数。              #include <iostream> using namespace std; const double pi=3.14; class BaseEllipse //抽象基类 含有圆跟椭圆的公共成员 { private: double x; double y; public: BaseEllipse(double t_x=0,double t_y=0) { x=t_x; y=t_y; } virtual ~BaseEllipse(){} void Move(int nx,int ny) { x=nx; y=ny; cout<<"中心坐标为:"<<"("<<x<<","<<y<<")"<<endl; }

virtual void Area()const=0;//纯虚函数结尾处为 “=0” 在类中可以只定义,不用实现

};class Circle:public BaseEllipse //圆{private: double r;public: Circle(double t_x=0,double t_y=0,double t_r=0); //半径和中心坐标 Circle(const BaseEllipse & ba,double t_r=0); void Area()const;};class Ellipse:public BaseEllipse //椭圆{private: double a; double b;public: Ellipse(double t_x=0,double t_y=0,double t_a=0,double t_b=0); Ellipse(const BaseEllipse & p,double t_a=0,double t_b=0); void Area()const;};/*圆*/Circle::Circle(double t_x,double t_y,double t_r):BaseEllipse(t_x,t_y){ r=t_r;}Circle::Circle(const BaseEllipse & ba,double t_r):BaseEllipse(ba){ r=t_r;}void Circle::Area()const{ cout<<pi*r*r<<endl;}/*椭圆*/Ellipse::Ellipse(double t_x,double t_y,double t_a,double t_b):BaseEllipse(t_x,t_y){ a=t_a; b=t_b;}Ellipse::Ellipse(const BaseEllipse & ba,double t_a,double t_b):BaseEllipse(ba){ a=t_a; b=t_b;}void Ellipse::Area()const{ cout<<0.5*a*b<<endl;}int main(){ Circle c1(0,0,5); c1.Move(1,2); c1.Area(); Ellipse e1(0,0,7,8); e1.Move(3,4); e1.Area(); return 0;}

转载于:https://www.cnblogs.com/JPAORM/archive/2012/03/20/2510025.html

【C++ Primer】第十三章 类继承相关推荐

  1. 《C++ Primer Plus(第六版)》(25)(第十三章 类继承 笔记)

    1.派生类构造函数的要点: 首先创建基类对象; 应通过成员初始化列表将基类的初始化信息传递给基类的构造函数; 派生类构造函数应初始化新增的数据成员 2.首先执行派生类的析构函数,然后自动调用基类的析构 ...

  2. C++ primer Plus(第六版)第十三章 类继承 章节编程练习答案

    1.以下面的类声明为基础: 派生出一个Classic类,并添加一组char成员,用于存储指出CD中主要作品的字符串.修改上述声明,使基类的所有函数都是虚的.如果上述定义声明的某个方法并不需要,则请删除 ...

  3. 第二十三章 类关键字 - Language

    文章目录 第二十三章 类关键字 - Language 用法 详解 对子类的影响 默认 第二十三章 类关键字 - Language 指定用于实现此类方法的默认语言. 用法 若要指定用于实现此类中的方法的 ...

  4. C++ primer 第7章 类

    成员函数的声明必须在类的内部,定义则既可以在类的内部,也可以在类的外部. 作为接口组成部分的非成员函数,它们的定义和声明都在类的外部. 类可以允许其他类或者函数访问它的非公有成员,方法是令其他类或函数 ...

  5. C++ Primer 第十三章 拷贝控制

    当定义一个类时,我们显式或隐式指定在此类型的对象执行拷贝,移动,赋值,销毁时做什么,通过拷贝构造函数,拷贝赋值运算符,移动构造函数,移动赋值运算符和析构函数. 拷贝赋值与销毁 如果构造函数的第一个参数 ...

  6. java钝角三角形怎么判断,java-第十三章-类的无参方法(一)-根据三角形的三条边长,判断是直角,锐角还是钝角三角形...

    package 本章总结; public class A03class { public boolean showA(int a ,int b ,int c){ boolean con=false; ...

  7. java-第十三章-类的无参方法(一)-根据三角形的三条边长,判断是直角,锐角还是钝角三角形...

    package 本章总结;public class A03class {public boolean showA(int a ,int b ,int c){boolean con=false;if(( ...

  8. PTA 7-2 动物世界 (15分) c++ 第5章类继承

    题目 补充程序 : 1.实现Mammal类的方法 2.由Mammal类派生出Dog类,在Dog类中增加itsColor成员(COLOR类型) 3.Dog类中增加以下方法: constructors: ...

  9. java-第十三章-类的无参方法(一)-实现客户姓名的添加和显示

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 3 ...

最新文章

  1. html表格立体效果,用HTML实现凸(凹)起的立体效果的表格
  2. termux配置python_termux python环境
  3. 生产事故 java_记一次生产事故:30万单就这样没了!
  4. 分布式版本控制系统Git学习资源收集汇总
  5. 三分钟Docker-环境搭建篇
  6. leetcode201. 数字范围按位与
  7. Vue3---安装Element-Plus组件库
  8. Flutter通过MethodChannel实现Flutter 与Android iOS 的双向通信
  9. 【Clickhouse】Clckhouse 视图 可以插入 但是查询不到
  10. 使用VSTS为ASP.NET Core构建DevOps CI/CD管道
  11. I/O多路复用技术是什么?
  12. docker︱在nvidia-docker中使用tensorflow-gpu/jupyter
  13. Linq to Oracle 使用教程(十)绑定数据到 GridView
  14. html手机页面怎么长按不出复制,HTML -----对于手机页面长按会粘贴复制的禁用
  15. 中国平面设计指导价格
  16. 【数据库查询--电影制片系列】-- 检索出Studio表中制片公司st1的地址。
  17. 树莓派(Raspberry )开机自动启动Python程序
  18. Born to Win: Find Your Success Code by Zig Ziglar and Tom Ziglar
  19. 线性代数 --- 三种计算矩阵的行列式的方法之二 莱布尼兹展开法(个人笔记扫描版)
  20. 大学数学学习参考书点评之数学分析部分(转)

热门文章

  1. linux下简单限制网卡速度
  2. Div Vertical Menu ver2
  3. 用Response.Filter生成静态页
  4. 走进我的交易室08_有条理的交易者
  5. 中gcd函数_函数和模块的使用
  6. 一文讲清如何正确选择图表,学会后再也不会用错图表
  7. 从可视化模板,到数据仓库、数字化的资料,我整理并分享出来
  8. int 转CString
  9. pool win10提示bad_快速解决Win10出现Bad pool caller蓝屏故障的技巧
  10. auto.js适合安卓小米6,朋友圈触控点赞