12.0 class inheritance

Chapter 12: Class Inheritance

Deriving a Class (类的派生)

inheritance

  • 可以从一个类里面继承成员
    • Base class(父类)
    • Derived class(子类)
  • C++ 支持多个继承和多层继承
    • 多个继承:一个子类可以有多个父类
    • 多层继承:一个子类可以被孙子类继承
class base
{
  public:
    int a;
    int b;
};
class Derived: public Base
{
  public:
    int c;
};
class Derived: public Base1,public Base2{....};

Constructor

  • 举例说明一个派生类构造函数的执行过程
    • 申请内存
    • 派生的构造函数被调用
      • 首先通过父类的构造函数创建一个父类的对象
      • 成员初始化列表初始化成员
      • 最后执行子类构造函数的主体
class Derived: public Base
{
  public:
    int c;
    Derived(int c): Base(c - 2, c - 1), c(c)
    {
        this->a += 3; //it can be changed after initialization
        cout << "Constructor Derived::Derived(" << c << ")" << endl;
    }
    ....
};

Destructor

  • 子类的析构函数先被调用
  • 然后父类的析构函数再被调用
#include <iostream>
using namespace std;

class Base
{
  public:
    int a;
    int b;
    Base(int a = 0, int b = 0)
    {
        this->a = a;
        this->b = b;
        cout << "Constructor Base::Base(" << a << ", " << b << ")" << endl;
    }
    ~Base()
    {
        cout << "Destructor Base::~Base()" << endl;
    }
    int product()
    {
        return a * b;
    }
    friend std::ostream & operator<<(std::ostream & os, const Base & obj)
    {
        os << "Base: a = " << obj.a << ", b = " << obj.b;
        return os;
    }
};

class Derived: public Base
{
  public:
    int c;
    Derived(int c): Base(c - 2, c - 1), c(c)
    {
        this->a += 3; //it can be changed after initialization
        cout << "Constructor Derived::Derived(" << c << ")" << endl;
    }
    ~Derived()
    {
        cout << "Destructor Derived::~Derived()" << endl;
    }
    int product()
    {
        return Base::product() * c;
    }
    friend std::ostream & operator<<(std::ostream & os, const Derived & obj)
    {
        // call the friend function in Base class
        os << static_cast <const Base&> (obj) << endl;

        os << "Derived: c = " << obj.c;
        return os;
    }
};

int main()
{
    {
        Base base(1, 2);
        cout << base << endl;
    }
    cout << "----------------------" << endl;
    {
        Derived derived(5);
        cout << derived << endl;
        cout << "Product = " << derived.product() << endl; 
    }
    return 0;
}

out:

Constructor Base::Base(1, 2)
Base: a = 1, b = 2
Destructor Base::~Base()
----------------------
Constructor Base::Base(3, 4)              #父类的构造函数先被调用
Constructor Derived::Derived(5)
Base: a = 6, b = 4
Derived: c = 5
Product = 120
Destructor Derived::~Derived()           #子类的析构函数先被调用
Destructor Base::~Base()            

Access Control (protected)

Member Access

  • Public members: accessible anywhere
  • Private member : only accessible to the members and friends of that class

    只能在类的内部和友元函数中被访问

class Person{
  private:
    int n;// private member
  public:
    Person() : n(10){}  //this ->n is accessible
    Person(const Person& other): n(other.n){}  // other.n is accessible 
    void set(int n) {this->n = n;}  //this ->n is accessible
    void set(const Person& other){this->n =other.n;}//this->n and other.n are accessible 
};
  • Protected member : accessible to the members and friends of that class

    类的内部,子类内部以及友元函数可以访问

class Base 
{
  protected:
    int n;
  private:
    void foo1(Base& b)
    {
        n++;    // Okay
        b.n++;  // Okay
    }
};

class Derived : public Base 
{
    void foo2(Base& b, Derived& d) 
    { 
        n++;        //Okay
        this->n++;  //Okay
        //b.n++;      //Error. You cannot access a protected member through base
        d.n++;      //Okay
    }
};
 
void compare(Base& b, Derived& d) // a non-member non-friend function
{
    // b.n++; // Error
    // d.n++; // Error
}

Public Inheritance

  • Public members of base class
    • 在子类中仍然时public
    • 任何地方可以访问
  • Protected members of the base class
    • 在子类中仍然是protected
    • 只能在子类中访问
  • Private members of base class
    • 无法在子类中访问

Protected inheritance

  • Public members and Protected members of base class
    • 在子类中都变成protected members
    • 只能在子类中访问到
  • Private members of base class
    • 无法在子类中访问

Private inheritance

私有继承后子类就无法再被继承

  • Public members and Protected members of base class
    • 在子类中都变成Private members
    • 只能在子类中访问到
  • Private members of base class
    • 无法在子类中访问

Static and Dynamic Binding

  • 静态绑定:编译器哪一个函数被调用
  • 动态绑定:在运行时确实被调用的函数

Virtual Functions(虚函数)

一个用和不用虚函数之间区别的例子

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

class Person
{
  public:
    string name;
    Person(string n): name(n){}
    
    void print()
    //virtual void print()
    {
        cout << "Name: " << name << endl;
    }
};
class Student: public Person
{
  public:
    string id;
    Student(string n, string i): Person(n), id(i){}
    void print() 
    {
        cout << "Name: " << name;
        cout << ". ID: " << id << endl;
    }
};

void printObjectInfo(Person & p)
{
    p.print();
}
int main()
{
    {
        Student stu("yu", "2019");
        printObjectInfo(stu);  
    }

    {
        Person * p = new Student("xue", "2020");
        p->print(); //if print() is not a virtual function, different output
        delete p; //if its destructor is not virtual
    }
    return 0;
}

out:

// if print() is not a virtual function,print() of base class is called.  
Name: yu
Name: xue
// if print() is a virtual function,print() of child class is called.
Name: yu. ID: 2019 
Name: xue. ID: 2020
  • 关键词 “ virtual” 会使得这个函数成为父类以及所有子类的虚函数
  • 函数一旦变成虚函数,这个函数就会采用动态绑定,再运行时才被确定被调用函数
  • 父类的函数被设置为虚函数,子类中同名同参数的函数自动变成虚函数
  • 纯虚函数
    • 无实现、无定义,只是一个接口
    • 存在纯虚函数的这个类无法创建对象
    • 一般这样的类,是当父类用
class Person2
{
  public:
    string name;
    Person2(string n): name(n){}
    virtual void print() = 0;  // 一个纯虚函数
};
  • 析构函数都是虚函数

    如果析构函数不是虚函数,那么new一个子类对象赋给父类指针,程序结束后只会调用到父类的析构函数,而不会调用子类的析构函数,存在很多风险。

{
    Person * p = new Student("xue", "2020");
    p->print(); //if print() is not a virtual function, different output
    delete p; //if its destructor is not virtual
}

Dynamic Memory Management

  • 如果父类中需要动态内存管理,子类不需要
    • 只在父类中进行Hard copy即可(重新自定义一个copy constructor和copy assignment operator)
  • 如果子类也需要动态内存管理
    • 在子类中再进行一次hard copy

image-20220306211259284

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值