• 学习:类和对象——继承


    继承:

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

    继承的基本语法: 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、利用虚继承可以解决菱形继承问题

  • 相关阅读:
    UVa OJ 148 Anagram checker (回文构词检测)
    UVa OJ 134 LoglanA Logical Language (Loglan逻辑语言)
    平面内两条线段的位置关系(相交)判定与交点求解
    UVa OJ 130 Roman Roulette (罗马轮盘赌)
    UVa OJ 135 No Rectangles (没有矩形)
    混合函数继承方式构造函数
    html5基础(第一天)
    js中substr,substring,indexOf,lastIndexOf,split等的用法
    css的textindent属性实现段落第一行缩进
    普通的css普通的描边字
  • 原文地址:https://www.cnblogs.com/zpchcbd/p/11867939.html
Copyright © 2020-2023  润新知