C/C++教程

C++核心编程 4 类和对象 - 继承(6)

本文主要是介绍C++核心编程 4 类和对象 - 继承(6),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

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

  有些类与类之间存在从属关系,下一级别的类除了属于上一级别的类的部分共性之外,还有自己的特性。此时可以考虑用继承来减少代码量;

4.6.1 继承的基本语法

  例如在网站中,都有公共的头部、底部,甚至公共的左侧列表,只有中心内容不同。

普通实现:

 

//普通实现
class Java
{
public:
    void header()
    {
        cout << "首页、公开课、登录、注册...(公共头部)" << endl;
    }
    void footer()
    {
        cout << "帮助中心、交流合作、联系我们...(公共底部)" << endl;
    }
    void left()
    {
        cout << "C++、Java、Python...(公共分类列表)" << endl;
    }
    void content()
    {
        cout << "Java 学科视频" << endl;
    }
    
};

class Python
{
public:
    void header()
    {
        cout << "首页、公开课、登录、注册...(公共头部)" << endl;
    }
    void footer()
    {
        cout << "帮助中心、交流合作、联系我们...(公共底部)" << endl;
    }
    void left()
    {
        cout << "C++、Java、Python...(公共分类列表)" << endl;
    }
    void content()
    {
        cout << "Python 学科视频" << endl;
    }
};

class CPP
{
public:
    void header()
    {
        cout << "首页、公开课、登录、注册...(公共头部)" << endl;
    }
    void footer()
    {
        cout << "帮助中心、交流合作、联系我们...(公共底部)" << endl;
    }
    void left()
    {
        cout << "C++、Java、Python...(公共分类列表)" << endl;
    }
    void content()
    {
        cout << "C++ 学科视频" << endl;
    }
};

void test1()
{
    cout << "Java下载视频页面如下:" << endl;
    Java ja;
    ja.header();
    ja.footer();
    ja.left();
    ja.content();
    cout << "-----------------------------------------------------" << endl;
    cout << "Python下载视频页面如下:" << endl;
    Python py;
    py.header();
    py.footer();
    py.left();
    py.content();
    cout << "-----------------------------------------------------" << endl;
    cout << "C++下载视频页面如下:" << endl;
    CPP cpp;
    cpp.header();
    cpp.footer();
    cpp.left();
    cpp.content();


}

int main()
{
    test1();

    system("pause");
    return 0;
}

 

继承实现:

 

//继承实现
class BasePage   //公共页面类
{
public:
    void header()
    {
        cout << "首页、公开课、登录、注册...(公共头部)" << endl;
    }
    void footer()
    {
        cout << "帮助中心、交流合作、联系我们...(公共底部)" << endl;
    }
    void left()
    {
        cout << "C++、Java、Python...(公共分类列表)" << endl;
    }
};

//Java页面
class Java :public BasePage
{
public:
    void content()
    {
        cout << "Java 学科视频" << endl;
    }
};
//Python页面
class Python :public BasePage
{
public:
    void content()
    {
        cout << "Python 学科视频" << endl;
    }
};
//C++页面
class CPP :public BasePage
{
public:
    void content()
    {
        cout << "C++ 学科视频" << endl;
    }
};
void test1()
{
    cout << "Java下载视频页面如下:" << endl;
    Java ja;
    ja.header();
    ja.footer();
    ja.left();
    ja.content();
    cout << "-----------------------------------------------------" << endl;
    cout << "Python下载视频页面如下:" << endl;
    Python py;
    py.header();
    py.footer();
    py.left();
    py.content();
    cout << "-----------------------------------------------------" << endl;
    cout << "C++下载视频页面如下:" << endl;
    CPP cpp;
    cpp.header();
    cpp.footer();
    cpp.left();
    cpp.content();
}

int main()
{
    test1();

    system("pause");
    return 0;
}

 

继承的好处:减少代码量

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

子类 也称为 派生类

父类 也成为 基类

 

4.6.2 继承方式

继承的方式一共有三种:公共继承、保护继承、私有继承

class A

{

public:

  int a;

protected:

  int b;

private:

  int c;

}

 

 

 4.6.3 继承中的对象模型

 

class BasePage   //公共类
{
public:
    int a;
protected:
    int b;
private:
    int c;
};

//利用VS2017开发人员命令提示工具查看对象模型
//跳转盘符 如想跳至D盘 就 D: 回车
//跳转文件路径  cd  具体文件路径复制粘贴过来
//查看命令cl /d1 reportSingleClassLayout查看类名 项目文件名
//cl /d1 reportSingleClassLayoutSon Project1(Tab键补齐)

class Son :public BasePage
{
public:
    int d;
};

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

    system("pause");
    return 0;
}

 4.6.4 继承中构造与析构顺序

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

问题:父类和子类的构造函数和析构函数谁先谁后

//继承中的构造和析构顺序
class Base  //公共类
{
public:
    Base()
    {
        cout << "Base父类构造函数!" << endl;
    }
    ~Base()
    {
        cout << "Base父类析构函数!" << endl;
    }
};

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

void test1()
{
    //Base b;
    Son s;
}
int main()
{
    test1();

    system("pause");
    return 0;
}

 

//继承中的构造和析构顺序
class Base  //公共类
{
public:
    Base()
    {
        cout << "Base父类构造函数!" << endl;
    }
    ~Base()
    {
        cout << "Base父类析构函数!" << endl;
    }
};

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

void test1()
{
    Base b;
    Son s;
}
int main()
{
    test1();

    system("pause");
    return 0;
}

4.6.5 继承同名成员处理方法

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

访问父类同名成员  需要加作用域

//继承中同名成员处理
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;
};
//同名成员属性
void test1()
{
    Son s;
    cout << "Son  m_A = " << s.m_A << endl;
    //如果通过子类访问对象 访问到父类中同名成员,需要加作用域
    //就近原则 父不明要 子不明给
    cout << "Base m_A = " << s.Base::m_A << endl;
}
//同名成员函数
void test2()
{
    Son s;
    s.func();
    //如果通过子类访问对象 访问到父类中同名函数,需要加作用域
    s.Base::func();
    
    //Base类中的重载函数s.func(int a) 如果把子类中的void func()屏蔽掉,就不会报错
    //如果子类中出现和父类同名的成员函数,子类的同名成员会隐藏掉父类中所有同名成员函数  Base:func()和func(int a)
    //如果想访问到父类中被隐藏的同名成员函数,需要加作用域
    //s.func(100);
    s.Base::func(100);
}
int main()
{
    test1();
    test2();
    system("pause");
    return 0;
}

总结:

1、子类对象可以直接访问到子类中的同名成员;

2、子类对象可以加作用域访问到父类中的同名成员;

3、当子类中出现和父类同名的成员函数,子类的同名成员会隐藏掉父类中所有同名成员函数,可以通过加作用域访问到父类中的同名成员函数;

4.6.6 继承同名静态成员处理方法

 

//继承中同名静态成员处理
class Base  //公共类
{
public:    
    static int m_A;
    static void func()
    {
        cout << "Base - static void func()" << endl;
    }

    //重载版本
    static void func(int a)
    {
        cout << "Base - static void func(int a)" << endl;
    }
}; int Base::m_A = 100;

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

}; int Son::m_A = 200;
//同名静态成员属性
void test1()
{
    //1、通过对象访问
    cout << "通过对象访问:" << endl;
    Son s;
    cout << "Son  m_A = " << s.m_A << endl;
    cout << "Base m_A = " << s.Base::m_A << endl;


    //2、通过类名访问
    cout << "通过类名访问:" << endl;
    cout << "Son   m_A = " << Son::m_A << endl;
    cout << "Base  m_A = " << Son::Base::m_A << endl;     
    //Son::Base  通过类名的方式访问Base       ||        Son::Base::m_A 通过类名的方式访问Base作用域下的m_A
}
//同名静态成员函数
void test2()
{
    //1、通过对象访问
    cout << "通过对象访问:" << endl;
    Son s;
    s.func();
    //如果通过子类访问对象 访问到父类中同名函数,需要加作用域
    s.Base::func();
    
    //2、通过类名访问
    cout << "通过类名访问:" << endl;
    Son::func();
    Son::Base::func();

    //子类出现和父类同名静态成员函数,也会隐藏掉父类中所有同名成员函数
    //如果通过子类访问对象 访问到父类中同名函数,需要加作用域
    Son::Base::func(100);
}
int main()
{
    //test1();
    test2();
    system("pause");
    return 0;
}

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

4.6.7 多继承语法

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

语法: class  子类 :继承方式 父类1 ,继承方式 父类2...

 

#include<iostream>
using namespace std;

//多继承语法
class Base1
{
public:
    Base1()
    {
        m_A = 100;
        m_E = 500;
    }
    int m_A;
    int m_E;
};

class Base2
{
public:
    Base2()
    {
        m_B = 200;
        m_E = 600;
    }
    int m_B;
    int m_E;
};


//子类 需要继承Base1和Base2
//语法: class 子类 :继承方式 父类1,继承方式 父类2
class Son :public Base1, public Base2
{
public:
    Son()
    {
        m_C = 300;
        m_D = 400;
    }
    int m_C;
    int m_D;
};

void test1()
{
    Son s;
    cout << "sizeof Son = " << sizeof(s) << endl;
    cout << "m_A = " << s.m_A << endl;
    //当父类中出现同名成员,需要加作用域区分
    cout << "Base1 m_E = " << s.Base1::m_E << endl;
    cout << "Base2 m_E = " << s.Base2::m_E << endl;
}

int main()
{
    test1();
    system("pause");
    return 0;
}

总结:多继承中如果父类中出现了同名情况,子类使用时要加作用域

4.6.8 菱形继承

概念:两个派生类继承同一个基类,又有某个类同时继承两个派生类。也称钻石继承

例子:

 

#include<iostream>
using namespace std;

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

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

//羊驼类
class SheepTuo :public Sheep,public Tuo{};
void test1()
{
    SheepTuo st;
    st.Sheep::m_Age = 18;
    st.Tuo::m_Age = 28;
    //当菱形继承时,两个父类拥有相同的数据,需要加作用域以区分
    cout << "st.Sheep::m_Age = " << st.Sheep::m_Age << endl;
    cout << "st.Tuo::m_Age = " << st.Tuo::m_Age << endl;
    cout << "st.m_Age = " << st.m_Age << endl;

    //菱形继承导致数据有两份,造成资源浪费,增加内存开销。


}
int main()
{
    test1();
    system("pause");
    return 0;
}

 

这篇关于C++核心编程 4 类和对象 - 继承(6)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!