C++特性二:继承

作者:jicanmeng

时间:2014年11月08日


c++中,当一个新类从一个已经定义的类中派生后,新类不仅继承了原有类的属性和方法,而且还有拥有自己的属性和方法。被继承的类称为基类(base class)或超类(super class)或父类,在基类或父类基础上建立的新类称为派生类(derived class)或子类(sub class)。

在c++中,一个派生类的定义格式如下:

class <派生类名>:[<继承方式 1>] <基类名>, [<继承方式2>] <基类名>,...
{
};

有四点需要注意:

  1. 一个派生类和一个一般类的定义格式基本相同,唯一的区别在于,派生类定义时派生类名后面是由冒号":"引导的基类列表。
  2. 基类列表中,若指定基类只有一个,则为单继承方式;若有多个基类,则为多继承方式。当有多个基类时,基类之间需要用逗号分隔。
  3. 各个基类名前面需要指定继承方式,用于限定派生类继承自基类中的属性和方法的访问权限。c++继承方式有三种:public,protected,private。若继承方式没有指定,则默认指定为private方式。
  4. 基类必须是在派生类定义前已经定义过的类。若在派生类后面定义,而仅仅在派生类定义前进行基类的提前声明,则是不合法的。

类的继承使基类可以向派生类传递基类的属性和方法。但在派生类中访问基类的属性和方法不仅取决于基类成员的访问属性,而且取决于其继承方式。

1. 如果继承方式是public,那么基类中的访问属性为public的成员在派生类中的属性为public,基类中的访问属性为protected的成员在派生类中的属性为protected,基类中的访问属性为private的成员在派生类中不可访问。

2. 如果继承方式是protected,那么基类中的访问属性为public的成员在派生类中的属性为protected,基类中的访问属性为protected的成员在派生类中的属性为protected,基类中的访问属性为private的成员在派生类中不可访问。

3. 如果继承方式是private,那么基类中的访问属性为public的成员在派生类中的属性为private,基类中的访问属性为protected的成员在派生类中的属性为private,基类中的访问属性为private的成员在派生类中不可访问。

#include <iostream>
#include <cstring>
using namespace std;

class CPerson
{
public:
    CPerson(string strName = "", int nAge = 0, char sex='M')
    {
        m_strName = strName;
        m_nAge = nAge;
        m_sex = sex;
        cout << "CPerson constructor called." << endl;
    }
    string GetName(){
        return m_strName;
    }
    char  GetSex(){
        return m_sex;
    }
    int GetAge(){
        return m_nAge;
    }
    ~CPerson()
    {
      cout << "CPerson destructor called." <<s endl;
    }

    string m_strName;
    char m_sex;
    int m_nAge;
};
class CStudent:public CPerson
{
public:
    CStudent(string strName = "", int nAge = 0, char sex='M', string strStuno = "")
        :CPerson(strName,nAge,sex)
    {
        m_strStuno = strStuno;
        cout << "CStudent constructor called." << endl;
    }
    string GetStuno(){
        return m_strStuno;
    }
    ~CStudent()
    {
      cout << "CStudent destructor called." << endl;
    }
private:
    string m_strStuno;
};
int main()
{
    CStudent one("XiaoMing", 19, 'M', "5040108");
    one.m_strName = "DaMeng";
    cout << "Name: " << one.m_strName << endl <<
        "sex: " << one.m_sex << endl <<
        "age: " << one.m_nAge << endl <<
        "student number: " << one.GetStuno() << endl;
    return 0;
}

以下是运行结果:

[jicanmeng@andy tmp]$ ./a.out
				CPerson constructor called.
				CStudent constructor called.
				Name: DaMeng
				sex: M
				age: 19
				student number: 5040108
				CStudent destructor called.
				CPerson destructor called.
			[jicanmeng@andy tmp]$

可以得出,派生类对象构建的时候,首先构建基类对象,然后才构建派生类对象(或者说,首先构建派生类对象的基类部分,然后再构建剩余部分)。在析构的时候,首先析构派生类对象,然后再析构基类对象

看一看learncpp.com上面对继承的一些描述:

Inheritance in C++ takes place between classes. When one class inherits from another, the derived class inherits the variables and functions of the base class. These variables and functions become part of the derived class.

这里有一点需要注意:在定义派生类CStudent的构造函数头后面还有一个":"引导的基类的构造函数。如果没有这个构造函数,那么就会调用基类的默认构造函数。

我们在前面类中成员的初始化中也提到过,构造函数头后面可以跟由冒号":"引导的对象成员初始化列表。其实,派生类的构造函数头后面可以同时带有基类的构造函数和自己成员的初始化列表。将上面的程序中派生类的构造函数的定义稍微修改下:

#include <iostream>
class CStudent:public CPerson
{
public:
    CStudent(string strName = "", int nAge = 0, char sex='M', string strStuno = "")
        :CPerson(strName,nAge,sex),m_strStuno(strStuno)
    {
    }
    string GetStuno(){
        return m_strStuno;
    }
private:
    string m_strStuno;
};

这也是完全没有问题的。

参考资料

  1. <<C++实用教程>> 电子工业出版社 郑阿奇 主编 丁有和 编著
  2. The C++ Tutorial:
    http://www.learncpp.com/cpp-tutorial/112-basic-inheritance-in-c/