继承

继承是面向对象三大特性之一

有些类与类之间存在特殊的关系

 

 可以发现,定义这些类时,下级别的成员除了拥有上一级的共性,还有自己的特性。

这个时候可以考虑用继承的技术,减少重复代码

继承的基本语法

#include <iostream>
using namespace std;

class Base {
    public:
        void header() {
            cout << "首页、公开课、登录、注册···(公共头部)" << endl; 
        }
        void footer() {
            cout << "帮助中心、交流合作、站内地图···(公共底部)" << endl;
        }
        void left() {
            cout << "Java、Python、C++···(公共分类列表)" << endl;
        }    
};

class Java : public Base{
    public:
        void contain() {
            cout << "Java学科视频" << endl;
        }
};

class Cpp : public Base{
    public:
        void contain() {
            cout << "cpp学科视频" << endl;
        }
};

void test01() {
    cout << "Java下载视频页面如下:" << endl;
    Java ja;
    ja.header();
    ja.footer();
    ja.left();
    ja.contain();
    cout << "------------------------ " << endl;
}

void test02() {
    cout << "cpp下载视频页面如下:" << endl;
    Cpp cpp;
    cpp.header();
    cpp.footer();
    cpp.left();
    cpp.contain();
    cout << "------------------------ " << endl;
}
int main() {
    test01();
    test02();
} 

语法:class 子类 : 继承方式 父类 {}

子类 也称 派生类

父类 也称 基类

 继承方式

继承的方式一共有三种:

  • 公共继承
  • 保护继承
  • 私有继承

 

 

 继承中的对象模型

问题:从父类继承过来的成员,哪些属于子类对象中?

#include <iostream>
using namespace std;

class Base {
    public:
        int m_A;
    protected:
        int m_B;
    private:
        int m_C;//也被子类继承了 
};


class Son : public Base {
    public:
        int m_D;
};

int main() {
    //父类中所有非静态的成员属性都会被子类继承下去
    //父类中私有的成员属性,是被编译器隐藏了,因此访问不到 ,但是也被继承了 
    cout << sizeof(Son) << endl; //16
} 

继承中构造和析构顺序

子类继承父类后,当创建子类对象,也会调用父类的构造函数 

问题:父类和子类的构造和析构顺序是谁先谁后?

#include <iostream>
using namespace std;

class Base {
    public:
        Base() {
            cout << "Base的构造函数" << endl;
        }
        ~Base()  {
            cout << "Base的析构函数" << endl;
        }
};


class Son : public Base {
    public:
        Son() {
            cout << "Son的构造函数" << endl;
        }
        ~Son()  {
            cout << "Son的析构函数" << endl;
        }
};

int main() {
    Son s;
//    Base的构造函数
//    Son的构造函数
//    Son的析构函数
//    Base的析构函数
} 

结论:继承中 先构造父类再构造子类,析构顺序与构造顺序相反

继承同名成员处理方式

问题:当子类与父类出现同名的成员,如何通过子类对象,访问到子类或者父类中同名的数据呢?

  • 访问子类同名成员  直接访问即可
  • 访问父类同名成员  需要加作用域
using namespace std;

class Base {
    public:
        Base() {
            m_A = 100;
        }
        void func() {
            cout << "Base - func()调用" << endl;
        }
        
        void func(int a) {
            cout << "Base - func(int a)调用" << endl;
        }
        int m_A;
};


class Son : public Base {
    public:
        Son() {
            m_A = 200;
        }
        
        void func() {
            cout << "Son - func()调用" << endl;
        }
        

        int m_A;
};

int main() {
    Son s;
    //同名成员属性 
    cout << s.m_A << endl; //200
    cout << s.Base::m_A << endl; //100
    
    //同名成员函数
    s.func();
    s.Base::func(); 
    
    //如果子类中出现和父类同名的成员函数,子类的同名成员会隐藏掉父类中所有同名成员函数(重载的也一样)
    //如果想访问父类中被隐藏的同名成员函数,需要加作用域 
    s.Base::func(100);
} 

总结:

  1. 子类对象可以直接访问到子类中同名成员
  2. 子类对象加作用域可以访问到父类同名成员
  3. 当子类与父类拥有同名的成员函数,子类会隐藏父类中同名成员函数,加作用域可以访问到父类中同名函数

继承同名静态成员处理方式

问题:继承中同名的静态成员在子类对象上如何进行访问?

  • 访问子类同名成员,直接访问即可
  • 访问父类同名成员,需要加作用域
#include <iostream>
using namespace std;

class Base {
    public:
        static void func() {
            cout << "Base -static func()调用" << endl;
        }
        static int m_A;
};

int Base::m_A = 100;

class Son : public Base {
    public:
        static void func() {
            cout << "Son -static func()调用" << endl;
        }
        
        static int m_A;
};

int Son::m_A = 200;

int main() {
    Son s;
    
    //通过对象访问 
    cout << s.m_A << endl; //200
    cout << s.Base::m_A << endl; //100
    //通过类名访问
    cout << Son::m_A << endl; //200
    cout << Son::Base::m_A << endl; //100
    
    //成员函数同理 
} 

  总结:同名静态函数处理方式和非静态处理方式一样,只不过有两种访问方式(通过对象 和 通过类名)

多继承语法

C++允许一个类继承多个类

语法: class 子类 :继承方式 父类1,继承方式 父类2··· {} 

多继承可能会引发父类中有同名成员出现,需要加作用域区分

 菱形继承

菱形继承概念

  • 两个派生类继承同一个基类
  • 又有某个类同时继承着两个派生类
  • 这种继承被称为菱形继承,或者钻石继承

 

 菱形继承问题

  1. 羊继承了动物的数据,驼同样继承了动物的数据,当草泥马使用数据时,就会产生二义性
  2. 草泥马继承自 动物的数据继承了两份,但这份数据实际只有需要一份
#include <iostream>
using namespace std;

//动物类 
class Animal {
    public:
        int m_Age;
};

//利用虚继承 解决菱形继承问题
//继承之前加上关键字 virtual 变为虚继承
//Animal类 称为 虚基类 
//羊类 
class Sheep : virtual public Animal {
    
};

//驼类 
class Camel : virtual public Animal {
    
};

//羊驼类 
class SheepTuo : public Sheep, public Camel {
    
};

int main() {
    SheepTuo st;
    st.m_Age = 18;
} 

 

 

posted @ 2021-08-14 12:35  白藏i  阅读(46)  评论(0)    收藏  举报