二、面向对象之继承

一、继承的引出

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<string>
using namespace std;

class News
{
public:
    void header()
    {
        cout << "公共头部" << endl;
    }
    void footer()
    {
        cout << "公共底部" << endl;
    }
    void left()
    {
        cout << "左侧列表" << endl;
    }
    void content()
    {
        cout << "新闻播报" << endl;
    }
};

class YULE
{
public:
    void header()
    {
        cout << "公共头部" << endl;
    }
    void footer()
    {
        cout << "公共底部" << endl;
    }
    void left()
    {
        cout << "左侧列表" << endl;
    }
    void content()
    {
        cout << "娱乐八卦" << endl;
    }
};

void test()
{
    News news;
    news.header();
    news.footer();
    news.left();
    news.content();
    YULE yule;
    yule.header();
    yule.footer();
    yule.left();
    yule.content();
}

int main()
{
    test();
    return EXIT_SUCCESS;
}

// 代码重复率太高,冗余大
// 设置基类,解决冗余的问题
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<string>
using namespace std;

// 继承类的写法
// 抽象一个 基类的网页 重复的代码都写在这个网页上
class BasePage
{
public:
    void header()
    {
        cout << "公共头部" << endl;
    }
    void footer()
    {
        cout << "公共底部" << endl;
    }
    void left()
    {
        cout << "左侧列表" << endl;
    }
};

class News :public BasePage  // News 类继承 BasePage 类
{
public:
    
    void content()
    {
        cout << "新闻播报" << endl;
    }
};

class YULE:public BasePage // YULE 类继承 BasePage 类
{
public:
    void content()
    {
        cout << "娱乐八卦" << endl;
    }
};

void test()
{
    News news;
    news.header();
    news.footer();
    news.left();
    news.content();
    YULE yule;
    yule.header();
    yule.footer();
    yule.left();
    yule.content();
}


int main()
{
    test();
    return EXIT_SUCCESS;
}

二、继承方式

public: 共有继承
protected:保护继承
private: 私有继承

不管公有继承、私有继承、保护继承, 基类中的私有属性, 都不可以继承下去
公有继承 public:
  父类中的public 在子类中的是public
  父类中的protected 在子类中的是protected
保护继承 protected:
  父类中的public 在子类中的是protected
  父类中的protected 在子类中的是protected
私有继承 private:
  父类中的public 在子类中的是private
  父类中的protected 在子类中的是private

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<string>
using namespace std;

class Base1
{
public:
    int a;
protected:
    int b;
private:
    int c;
};

// 共有继承
class Son1 : public Base1
{
public:
    void func()
    {
        cout << a << endl;   // 基类中共有属性可以继承,还是 public
        cout << b << endl;   // 基类中保护属性可以继承, 还是 protected
        //cout << c << endl; // 基类中私有属性不可继承
    }
};

// 保护继承
class Son2 : protected Base1
{
public:
    void func()
    {
        cout << a << endl;   // 基类中共有属性可以继承,但是 protected
        cout << b << endl;   // 基类中保护属性可以继承, 还是 protected
        //cout << c << endl; // 基类中私有属性不可继承
    }
};

// 私有继承
class Son3 : private Base1
{
public:
    void func()
    {
        cout << a << endl;   // 基类中共有属性可以继承,但是 private
        cout << b << endl;   // 基类中保护属性可以继承, 还是 private
        //cout << c << endl; // 基类中私有属性不可继承
    }
};

class GrandSon :public Son3
{
public:
    void func()
    {
        //cout << a << endl; 访问不到, 因为到Son3中, a已经是私有的了
    }
};

void myFunc()
{
    Son1 s1;
    s1.a;
    Son2 s2;
    // s2.a;  类外不能访问 protected
    Son3 s3;
    // s3.a;  类外不能访问 private
}

int main()
{
    return EXIT_SUCCESS;
}

 

三、子类的大小

/*
    子类会继承父类中所有的内容, 包括私有属性,只是我们访问不到,编译器给隐藏了
*/

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<string>
using namespace std;

class BaseClass
{
public:
    int A;
protected:
    int B;
private:
    int C;
};

// 在子类中会继承父类的私有成员,只是被编译器被隐藏起来,所以访问不到私有成员
class Son : public BaseClass
{
public:
    int D;
};

void test()
{
    cout << sizeof(Son) << endl;  // 16, 子类会继承父类的私有成员,但是不能用
}

int main()
{
    test();
    return EXIT_SUCCESS;
}

 

四、继承中的构造与析构的顺序

/*
    子类创建对象时,先调用父类的构造,在调用自身构造, 析构的顺序正好相反
    子类会继承父类的成员属性和成员函数,但是不会继承父类的构造函数和析构函数
    如果父类中没有合适的默认构造,子类可以用初始化列表的方式显示的调用父类的其他构造。
*/
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<string>
using namespace std;

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

class Son : public BaseClass
{
public:
    Son()
    {
        cout << "Son的默认构造调用" << endl;
    }
    ~Son()
    {
        cout << "Son的的析构函数调用" << endl;
    }
};

class GrandSon : public Son
{
public:
    GrandSon()
    {
        cout << "GrandSon的默认构造调用" << endl;
    }
    ~GrandSon()
    {
        cout << "GrandSon的的析构函数调用" << endl;
    }
};

// 子类会继承父类的成员属性和成员函数,但是不会继承父类的构造函数和析构函数
void test()
{
    GrandSon g1;
    /*
        Base的默认构造调用
        Son的默认构造调用
        GrandSon的默认构造调用
        GrandSon的的析构函数调用
        Son的的析构函数调用
        Base的的析构函数调用
    */
}

class BaseClass2
{
public:
    BaseClass2(int a)
    {
        this->A = a;
        cout << "BaseClass2有参构造调用" << endl;
    }
    int A;
};

class Son2 : public BaseClass2
{
public:
    //Son2()  // 直接这样会报错,因为一开始就会先调用父类中不存在默认构造了
    //{
    //}
    Son2(int a) : BaseClass2(a) // 利用初始化列表方法显示调用 有参构造
    {

    }
};

void test02()
{
    Son2 son2(100);
}

int main()
{
    test();
    return EXIT_SUCCESS;
}

 

五、继承中的同名成员处理

/*
    如果子类和父类拥有同名的函数、属性,子类不会覆盖父类的成员属性和成员函数
    如果子类与父类的成员函数名称相同,子类会把父类的所有的同名的版本都隐藏, 想要调用父类的,需要加作用域
*/

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<string>
using namespace std;

class BaseClass
{
public:
    BaseClass()
    {
        this->A = 100;
    }
    void func()
    {
        cout << "父类的func无参调用" << endl;
    }
    void func(int a)
    {
        cout << "父类的func有参调用" << endl;
    }
    
    void func2()
    {
        cout << "父类的func2无参调用" << endl;
    }
    void func2(int a)
    {
        cout << "父类的func2有参调用" << endl;
    }
    int A;
};

class Son : public BaseClass
{
public:
    Son()
    {
        this->A = 200;
    }
    void func()
    {
        cout << "Son的func调用" << endl;
    }
    int A;
};

// 如果子类和父类拥有同名的函数、属性,子类不会覆盖父类的成员属性和成员函数
// 如果子类与父类的成员函数名称相同,子类会把父类的所有的同名的版本都隐藏, 想要调用父类的,需要加作用域

void test()
{
    Son s1;
    cout << "s1.A = " << s1.A << endl;  // s1.A = 200
    // 想调用父类的A
    cout << "父类的A = " << s1.BaseClass::A << endl; // 父类的A = 100
    s1.func();   // Son的func调用
    //s1.func(2);  // 不能直接调用
    s1.BaseClass::func(); // 父类的func无参调用
    s1.func2();   // 父类的func2无参调用 , 子类没有,直接调用父类的方法
    s1.func2(2);  // 父类的func2有参调用
}

int main()
{
    test();
    return EXIT_SUCCESS;
}

 

六、继承中的静态成员处理

/*
    类似非静态成员处理, 想要访问父类的成员, 加上作用域
*/
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<string>
using namespace std;

class BaseClass
{
public:
    static void func()
    {
        cout << "base的func" << endl;
    }
    static void func(int a)
    {
        cout << "base的func(int)" << endl;
    }
    static int A;
};


class Son : public BaseClass
{
};

class Son2 : public BaseClass
{
public:
    static void func()
    {
        cout << "Son2的func" << endl;
    }
    static void func(int a)
    {
        cout << "Son2的func(int)" << endl;
    }
    static int A;
};

int BaseClass::A = 10;   // 类内声明,类外调用
int Son2::A = 20;

// 子类可以继承父类的静态变量
void test()
{
    cout << Son::A << endl;  // 10
    cout << Son2::A << endl; // 20
    // 访问Son2的父类的A
    cout << BaseClass::A << endl;  // 10

    Son2::func();  // Son2的func
    // 访问父类的同名函数
    BaseClass::func();  // base的func
    Son2::BaseClass::func(10); // base的func(int)
}


int main()
{
    test();
    return EXIT_SUCCESS;
}

七、多继承与菱形继承

7.1 多继承

/*
    多继容易出现二义性, 通过调用作用域可以解决
*/
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<string>
using namespace std;

class Base1
{
public:
    Base1()
    {
        this->A = 10;
    }
    int A;
};

class Base2
{
public:
    Base2()
    {
        this->B = 20;
    }
    int B;
};

// 多继容易出现二义性, 通过调用作用域可以解决
class Son : public Base1, public Base2
{
public:
    int C;
    int D;
};

void test()
{
    cout << sizeof(Son) << endl;  // 16
    Son s1;
    cout << "s1.A = " << s1.A << endl;  //10
    cout << "s1.B = " << s1.B << endl;  // 20
}

int main()
{
    test();
    return EXIT_SUCCESS;
}

 

7.2 菱形继承与虚继承

7.2.1 菱形继承的问题引出

/*
    SheepTuo 同时继承了 Sheep, Tuo。 这两个父类都存在 Age, SheepTuo自己使用的使用只需要一个 Age就行了,所以 SheepTuo就会多开辟了一些没必要空间
*/
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<string>
using namespace std;

class Animal
{
public:
    int Age;

};

class Sheep : public Animal
{
public:

};

class Tuo : public Animal
{
public:

};


// SheepTuo 同时继承了 Sheep, Tuo。 这两个父类都存在 Age, SheepTuo自己使用的使用只需要一个 Age就行了,所以 SheepTuo就会多开辟了一些没必要空间
// 菱形继承的解决方案: 虚继承
class SheepTuo : public Sheep, public Tuo
{
public:

};

void test()
{
    SheepTuo st;
    st.Sheep::Age = 10;
    st.Tuo::Age = 20;
    cout << st.Sheep::Age << endl;
    cout << st.Tuo::Age << endl;
}

int main()
{
    test();
    return EXIT_SUCCESS;
}

7.2.2 虚继承

/*
    在继承的类前面加上 virtual
*/
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<string>
using namespace std;

class Animal
{
public:
    int Age;

};

// 虚基类 Sheep
class Sheep :virtual public Animal
{
public:

};

// 虚基类 Tuo
class Tuo :virtual public Animal
{
public:

};


// SheepTuo 同时继承了 Sheep, Tuo。 这两个父类都存在 Age, SheepTuo自己使用的使用只需要一个 Age就行了,所以 SheepTuo就会多开辟了一些没必要空间
// 菱形继承的解决方案: 虚继承
class SheepTuo : public Sheep, public Tuo
{
public:

};

void test()
{
    SheepTuo st;
    st.Sheep::Age = 10;
    st.Tuo::Age = 20;
    // 因为是虚基类, 所以操作的是同一个 Age,所以结果应该是一样的
    cout << st.Sheep::Age << endl;  // 20
    cout << st.Tuo::Age << endl;    // 20
    cout << st.Age << endl;         // 20 同时也可以直接访问了,没有二义性的可能了
}

int main()
{
    test();
    return EXIT_SUCCESS;
}

 

posted on 2022-03-15 20:07  软饭攻城狮  阅读(9)  评论(0编辑  收藏  举报

导航