C++继承与派生

2017-06-25 23:00:59

c++中的继承和派生是面向对象编程中的一个重要内容,通过继承可以实现代码的复用,同时继承也是实现多态性的基础。

一、c++继承的基本形式

class 派生类名:继承方式 基类名,继承方式 基类名

{};

继承方式主要有三种,public ,private ,protected。

缺省条件下是private继承,三种中public继承用的最多,不同的继承方式决定了子类中从基类继承过来的成员的访问属性。

public继承:

基类的public,protected成员在子类中访问属性不变,子类新增的成员函数可以直接访问,对于基类的private成员依然是基类的私有,子类无法直接进行访问。

private继承:

基类的public,protected成员转变为子类的private成员,子类新增的成员函数可以进行访问,对于基类的private成员依然是基类的私有,子类无法直接进行访问。

protected继承:

基类的public,protected成员转变为子类的protected成员,子类新增的成员函数可以进行访问,对于基类的private成员依然是基类的私有,子类无法直接进行访问。

private继承和protected继承的区别是private继承的子类如果继续被继承,那么这些从其分类继承得到的数据将不会被其子类继承,而protected则是可以的。

二、c++继承的注意事项

(1)父类的构造函数和析构函数是不会被继承的,需要重写派生类的构造函数和析构函数。

派生类的成员数据中有来自父类的成员数据,因此在写派生类的构造函数的时候需要调用其父类的构造函数。

如果派生类的成员中有成员对象,那么也需要用成员对象名来进行初始化。

这两种都是用初始化表来进行初始化工作的。

(2)派生类构造函数、析构函数的调用顺序

  • 构造函数中首先先调用各个直接基类的构造函数,之后再调用成员对象的构造函数,最后才是新增成员的初始化。
  • 对于多继承有多个基类,那么其构造函数的调用顺序是按被继承时的声明顺序,从左到右一次调用,与初始化表的顺序无关
  • 对于成员对象的初始化也是一样,与他们的声明顺序有关,和构造函数中的初始化表的顺序无关。
  • 如果没有进行显示的调用,那么会调用其默认的构造函数
  • 子类的拷贝构造函数也要为各个直接基类的拷贝构造函数传递参数
//若 B 类是 C 类的基类,则 C 类的自定义拷贝构造函数可定义为:
C:: C (  C  &c1  )  : B ( c1 )  {   函数体   }
  • 在派生类的析构函数中不会显示调用基类的析构函数,系统会自动隐式调用,调用顺序和构造函数的调用顺序正好相反。先构造的后析构。
class A
{
    int x1,y1;
public:
    //构造函数
    A(int a=0,int b=0)
    {
        x1=a;
        y1=b;
        cout<<"调用A的构造函数了\n";
    }

    //拷贝构造函数
    A(A& a)
    {
        x1=a.x1;
        y1=a.y1;
        cout<<"调用A的拷贝构造函数了"<<endl;
    }

    //展示内容
    void show()
    {
        cout<<x1<<" "<<y1<<endl;
    }

    //析构函数,析构函数无参数且无返回值
    ~A()
    {
        cout<<"调用A的析构函数了"<<endl;
    }
};

class B
{
    int x2,y2;
public:
    //构造函数
    B(int a=0,int b=0)
    {
        x2=a;
        y2=b;
        cout<<"调用B的构造函数了\n";
    }

    //拷贝构造函数
    B(B& b)
    {
        x2=b.x2;
        y2=b.y2;
        cout<<"调用B的拷贝构造函数了"<<endl;
    }

    //展示内容
    void show()
    {
        cout<<x2<<" "<<y2<<endl;
    }

    //析构函数,析构函数无参数且无返回值
    ~B()
    {
        cout<<"调用B的析构函数了"<<endl;
    }
};

class C:public A,public B
{
    int x3,y3;
public:
    //形参写成int x3,int y3,也就是和成员函数重名的话,内部的数据会出错,所以,不要重名,改成a,b即可
    C(int x1,int y1,int x2,int y2,int a,int b):A(x1,y1),B(x2,y2)
    {
        x3=a;
        y3=b;
        cout<<"调用C的构造函数了"<<endl;
    }

    C(C& c):A(c),B(c)
    {
        x3=c.x3;
        y3=c.y3;
        cout<<"调用C的拷贝构造函数了"<<endl;
    }

    void show()
    {
        A::show();
        B::show();
        cout<<x3<<" "<<y3<<endl;
    }

    ~C()
    {
        cout<<"调用C的析构函数了"<<endl;
    }
};

int _tmain(int argc, _TCHAR* argv[])
{
    C c1(1,2,3,4,5,6);
    c1.show();
    C c2(c1);
    c2.show();
    return 0;
}

(3)赋值兼容规则

规定了基类和其子类之间的赋值规则。

对于公有派生,可以将派生类对象赋值给其基类,反之则是不被允许的。

具体体现为:

  • 基类对象=派生类对象
  • &基类对象的别名=派生类对象
  • *基类对象的指针=&派生类对象的地址

对于这种赋值,基类只能访问子类中从基类继承过来的那部分成员。

(4)继承过程中的二义性问题

继承过程中可能会出现二义性的问题。主要有两种形式的二义性。

一是在多继承中,两个父类中有同名的变量,这时如果是公有继承,那么子类中就会出现两个同名变量。解决方法有两种,一是用域作用符进行限定,二是使用同名隐藏。

二是在多继承中,两个父类的父类是同一个类,这时就需要使用虚基类的手段来进行解决。虚基类可以保证在间接继承的时候只保留一份共同基类的成员数据。

虚基类的定义:

class 派生类:virtual 继承方式 基类名

{};

  • 由虚基类直接或者间接派生出来的子类都必须列出对虚基类的构造函数,若未显示列出则调用默认构造函数
  • 最终建立对象的类称为最终派生类,只在最终派生类中调用基类的构造函数,而在基类的直接派生类中不掉用基类的构造函数,这样就避免了基类成员的重复继承问题
class B
{
    int b;
public:
    B(int x)
    {
        b=x;
        cout<<"调用了B的构造函数"<<endl;
    }

    ~B()
    {
        cout<<"调用了B的析构函数"<<endl;
    }
};

class B1:virtual public B
{
    int b1;
public:
    B1(int x,int y):B(x)
    {
        b1=y;
        cout<<"调用B1的构造函数了"<<endl;
    }

    ~B1()
    {
        cout<<"调用B1的析构函数了"<<endl;
    }
};

class B2:virtual public B
{
    int b2;
public:
    B2(int x,int y):B(x)
    {
        b2=y;
        cout<<"调用B2的构造函数了"<<endl;
    }

    ~B2()
    {
        cout<<"调用B2的析构函数了"<<endl;
    }
};

class C:public B1,public B2
{
    int c;
public:
    C(int a,int b,int c,int d):B1(a,b),B2(a,c),B(a)
    {
        c=d;
        cout<<"调用C的构造函数了"<<endl;
    }

    ~C()
    {
        cout<<"调用C的析构函数了"<<endl;
    }
};

int _tmain(int argc, _TCHAR* argv[])
{
    C c1(1,2,3,4);
    return 0;
}

时间: 2024-09-29 22:30:52

C++继承与派生的相关文章

程序设计实习MOOC / 继承和派生——编程作业 第五周程序填空题1

描述 写一个MyString 类,使得下面程序的输出结果是: 1. abcd-efgh-abcd- 2. abcd- 3. 4. abcd-efgh- 5. efgh- 6. c 7. abcd- 8. ijAl- 9. ijAl-mnop 10. qrst-abcd- 11. abcd-qrst-abcd- uvw xyz about big me take abcd qrst-abcd- 要 求:MyString类必须是从C++的标准类string类派生而来.提示1:如果将程序中所有 "My

四.OC基础--1.文档安装和方法重载,2.self和super&amp;static,3.继承和派生,4.实例变量修饰符 ,5.私有变量&amp;私有方法,6.description方法

四.OC基础--1.文档安装和方法重载, 1. 在线安装 xcode-> 系统偏好设置->DownLoads->Doucument->下载 2. 离线安装 百度xcode文档 3. 方法重载: 是指在一个类中定义多个同名的方法 在OC中没有重载 2.self和super&static, self和super: 1. self理解: 谁调用当前方法, self就代表谁. 比如: 在对象方法中,self代表的是对象, 因为只有对象才可以调用对象方法 在类方法中, self代表的

模块的封装之C语言类的继承和派生

[交流][微知识]模块的封装(二):C语言的继承和派生 在模块的封装(一):C语言的封装中,我们介绍了如何使用C语言的结构体来实现一个类的封装,并通过掩码结构体的方式实 现了类成员的保护.这一部分,我们将 在此的基础上介绍C语言类的继承和派生.其实继承和派生是一个动作的两种不同角度的表达 .当我们继承了一个基类而创造了一个新类时,派生的概念就诞生了.派生当然是从基类派生的.派生出来的类当然是继承了基类的 东西.继承和派生不是一对好基友,他们根本就是一个动作的两种不同的说法,强调动作的起始点的时候

3.继承与派生

1.类的继承与派生 - 类的继承:从已有类产生新类的过程.原有类称为基类或父类,产生的新类称为派生类或子类. - 派生类语法: class 派生类名:继承方式   基类名1,继承方式 基类名2,... { } - 单继承和多继承:基类个数决定 - 直接基类,间接基类 - 继承方式规定了如何访问从基类继承的成员 - 派生类成员是指除了从基类继承的所有成员之外,新增加的数据和函数成员 - 派生类生成过程:吸收基类成员->改造基类成员->添加新的成员,构造函数和析构函数都不被继承 2.访问控制 -

嵌入式linux C++语言(七)——继承与派生

嵌入式linux C++语言(七)--继承与派生 一.继承 在C++编程中软件可重用性(software reusability)是通过继承(inheritance)机制来实现的.类的继承,是新的类从已有类那里得到已有的特性.或从已有类产生新类的过程就是类的派生.原有的类称为基类或父类,产生的新类称为派生类或子类. 派生类的声明:class 派生类名:[继承方式] 基类名{派生类成员声明:};    一个派生类可以同时有多个基类,这种情况称为多重继承,派生类只有一个基类,称为单继承. 继承方式规

继承与派生,重载&lt;&lt;

///继承与派生 #include <iostream> using namespace std; class Point { public: Point (float a=0,float b=0):x(a),y(b) {} ///有默认参数的构造函数 void setPoint (float,float); ///重新设置坐标 ///读x的坐标,getX为常成员函数,只能访问类的数据,而不能更改 float getX() const { return x; } float getY() co

c++学习--继承与派生

继承和派生 1 含有对象成员(子对象)的派生类的构造函数,定义派生类对象成员时,构造函数的执行顺序如下: 1 调用基类的构造函数,对基类数据成员初始化: 2 调用对象成员的构造函数,对对象成员的数据成员初始化: 3 执行派生类的构造函数体,对派生类数据成员初始化. 代码如下:#include<iostream.h> class base{ int x; public: base(int i) { x=i; cout<<"基类的构造函数"<<endl;

面向对象(二)——继承、派生、组合以及接口

一.继承与派生 1.1 什么是继承 继承是一种创建新类的方式,在Python中,新建的类可以继承一个或多个父类,父类又可称为基类或超类,新建的类称为派生类或子类 Python中类的继承分为:单继承和多继承 class People: # 定义父类 def __init__(self,name,age): self.name=name self.age=age def walk(self): print('%s is walking' %self) class Teacher(People): #

C++学习笔记44:继承与派生

类的组合,类的继承 类的组合(汽车类,轮子类,此时可以把轮子类组合到汽车类:) 类的继承(交通工具类,汽车类,此时汽车类可以派生自交通工具类:) 组合:常用描述has a.. 继承:常用描述is a .. 如果既可以用组合又可以用派生解决,那首选组合方式: 继承与派生的目的 继承的目的:实现设计和代码的重用 派生的目的:当新的问题出现,原有程序无法解决,需要对原有的程序进行改造 派生类的构成 吸收基类的成员 改造基类的成员 添加新的成员 吸收基类的成员 默认情况下派生类包含了全部的基类中除了构造