zoukankan      html  css  js  c++  java
  • 学习:类和对象——继承

    继承:

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

    继承的基本语法: class 类名: public/protected/private 父类

    总结:

    继承的好处:可以减少重复的代码

    class A : public B;

    A 类称为子类 或 派生类

    B 类称为父类 或 基类

    派生类中的成员,包含两大部分:

    1、一类是从基类继承过来的,一类是自己增加的成员。

    2、从基类继承过过来的表现其共性,而新增的成员体现了其个性。


    继承方式:

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

    继承方式一共有三种:

    1、公共继承
    2、保护继承
    3、私有继承

    相比于其他语言来说,c++还可以自己定义以哪种方式来继承父类,其他语言默认都是public来继承的


    继承中的对象模型:

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

    示例代码:

    class Base
    {
    public:
    	int m_A;
    protected:
    	int m_B;
    private:
    	int m_C; //私有成员只是被隐藏了,但是还是会继承下去
    };
    
    //公共继承
    class Son :public Base
    {
    public:
    	int m_D;
    };
    
    void test01()
    {
    	cout << "sizeof Son = " << sizeof(Son) << endl;
    }
    
    int main() {
    
    	test01();
    
    	system("pause");
    
    	return 0;
    }
    

    以上我们发现输出的字节为16个字节,但是还不够直观,我们可以通过visual studio相应的工具来查看

    使用命令:cl /d1 reportSingleClassLayout查看的类名 所属文件名

    结论: 父类中私有成员也是被子类继承下去了,只是由编译器给隐藏后访问不到


    继承中构造和析构顺序:

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

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

    示例代码:

    #include<iostream>
    #include<string>
    
    using namespace std;
    
    class Father {
    public:
    
    	Father() {
    		cout << "这是父类的构造方法" << endl;
    	}
    
    	~Father() {
    		cout << "这是父类的析构方法" << endl;
    	}
    };
    
    class Son :public Father {
    
    public:
    	Son() {
    		cout << "这是子类的构造方法" << endl;
    	}
    
    	~Son() {
    		cout << "这是子类的析构方法" << endl;
    	}
    };
    
    void test01() { //因为我们需要看到析构方法的效果,所以我们在定义一个函数进行使用
    	Son s1;
    }
    
    int main() {
    	test01();
    	system("pause");
    	return 0;
    
    }
    

    结果:

    总结:子类继承父类,先调用父类的构造方法然后再子类的,对于析构来说则顺序相反


    继承同名成员处理方式:

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

    1、访问子类同名成员 直接访问即可
    2、访问父类同名成员 需要加作用域

    示例代码:

    #include<iostream>
    #include<string>
    
    using namespace std;
    
    class Fat {
    
    public:
    	void aaa() {
    		cout << "这是父类的aaa函数" << endl;
    	}
    
    	void bbb() {
    		cout << "这是父类的bbb函数" << endl;
    	}
    
    };
    
    class Son:public Fat {
    
    public:
    	void aaa() {
    		cout << "这是子类的aaa函数" << endl;
    	}
    };
    
    int main() {
    	Son s1;
    	s1.aaa(); //这样只能调用子类的aaa函数
    	s1.Fat::aaa(); //同名的情况下 通过修改Fat:: 作用域来调用父类的同名函数
    	s1.bbb(); //不同名的情况下,可以直接调用父类的函数
    
    	system("pause");
    	return 0;
    
    }
    

    总结:

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


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

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

    #include<iostream>
    #include<string>
    
    using namespace std;
    
    class Fat {
    
    public:
    	static int a;
    	static void aaa() {
    		cout << "这是父类的aaa函数" << endl;
    	}
    
    	static void bbb() {
    		cout << "这是父类的静态bbb函数" << endl;
    	}
    
    };
    
    int Fat::a = 10;
    
    class Son :public Fat {
    
    public:
    	static int b;
    	static void bbb() {
    		cout << "这是子类的静态aaa函数" << endl;
    	}
    };
    
    int Son::b = 15;
    
    int main() {
    	Son s1;
    	//通过对象来调用静态函数
    	s1.bbb(); // 调用子类的静态函数
    	s1.Fat::bbb(); // 同名的情况下,通过作用域来调用
    	s1.Fat::aaa(); // 没有同名,可以直接调用父类的静态函数
    
    	//通过类的方式来调用静态函数
    	Son::Fat::bbb(); // 第一个::是代表类名访问,第二个::代表访问父类的作用域下
    
    	system("pause");
    	return 0;
    
    }
    

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


    多继承语法:

    C++允许一个类继承多个类 ps.在java中是不允许一个类继承多个类,但是一个类可以继承多个接口,然后这是课外话

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

    C++实际开发中不建议用多继承,原因是多个继承,多个相同属性的话,都需要添加相应的作用域来进行调用,容易混淆

    示例代码:

    class Base1 {
    public:
    	Base1()
    	{
    		m_A = 100;
    	}
    public:
    	int m_A;
    };
    
    class Base2 {
    public:
    	Base2()
    	{
    		m_A = 200;  //开始是m_B 不会出问题,但是改为mA就会出现不明确
    	}
    public:
    	int m_A;
    };
    
    //语法:class 子类:继承方式 父类1 ,继承方式 父类2 
    class Son : public Base2, public Base1 
    {
    public:
    	Son()
    	{
    		m_C = 300;
    		m_D = 400;
    	}
    public:
    	int m_C;
    	int m_D;
    };
    
    
    //多继承容易产生成员同名的情况
    //通过使用类名作用域可以区分调用哪一个基类的成员
    void test01()
    {
    	Son s;
    	cout << "sizeof Son = " << sizeof(s) << endl;
    	cout << s.Base1::m_A << endl;
    	cout << s.Base2::m_A << endl;
    }
    
    int main() {
    
    	test01();
    
    	system("pause");
    
    	return 0;
    }
    

    菱形继承: ps.之前学python的时候菱形继承好像跟这个不太一样emm,到时候再说吧,唉

    菱形继承概念:

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

    菱形继承问题:

    羊继承了动物的数据,驼同样继承了动物的数据,当草泥马使用数据时,就会产生二义性。

    草泥马继承自动物的数据继承了两份,其实我们应该清楚,这份数据我们只需要一份就可以。

    示例代码:

    #include<iostream>
    #include<string>
    
    using namespace std;
    
    class Animal {
    public:
    	int age;
    };
    
    class Yang:virtual public Animal{};
    
    class Tuo :virtual public Animal{};
    
    class YangTuo:public Yang, public Tuo{};
    
    
    int main() {
    	
    	YangTuo ty1;
    	ty1.Yang::age = 38;
    	ty1.Tuo::age = 28;
    	cout << ty1.Yang::age << endl; //直接进行访问不明确,我们需要添加作用域,那我们就需要对父类的age进行赋值
    	cout << ty1.Tuo::age << endl;
    
    	cout << ty1.age << endl; //即使进行了上面两步赋值的操作还是不能直接访问当前对象的age,因为编译器还是不知道到底要访问哪一个,通过对virtual对父类进行修饰
    	system("pause"); 
    	return 0;
    
    }
    

    底层讲解原因参考:https://www.bilibili.com/video/av41559729?p=134

    总结:

    1、菱形继承带来的主要问题是子类继承两份相同的数据,导致资源浪费以及毫无意义
    2、利用虚继承可以解决菱形继承问题

  • 相关阅读:
    office(PPT、Word、Excel)功能目录
    《数商》笔记
    笔记模板
    如何运用思维导图安排考生读书计划(增订版)
    自制桌面图片
    selenium+AutoIt
    selenium中应用问题解决
    mysql卸载
    vue每次修改刷新当前子组件
    vue与dajngo
  • 原文地址:https://www.cnblogs.com/zpchcbd/p/11867939.html
Copyright © 2011-2022 走看看