天天看點

C++私有繼承和公有繼承的學習私有繼承保護繼承

私有繼承

使用私有繼承,基類的公有成員和保護成員都将成為派生類的私有成員。

使用私有繼承意味着基類方法将不能在外部直接使用,但可以在派生類的成員函數中使用他們。

保護繼承

使用保護繼承,基類的公有成員和保護成員都将成為派生類的保護成員。

使用保護繼承意味着基類方法将不能在外部直接使用,但可以在派生類的成員函數中使用他們。

執行個體一

#include <iostream>
#include <string>
// 基類
class Person
{
    private:    // 似有成員
        std::string m_name;   // 姓名
        int m_age;      // 年齡
    protected:   // 保護成員
        int get_age() const 
        {
            return m_age;
        }
    public:     // 公有成員
        Person(const char *name = "", int age = 0)   // 構造函數
            : m_name(name), m_age(age) {}   // 清單成員初始化
        virtual ~Person() {}  // 虛析構函數
        const std::string & get_name() const
        {
            return m_name;
        } 
        friend std::ostream& operator<<(std::ostream &os, const Person& p);     // 友元函數
};

// 派生類
class Student : private Person    // 似有繼承
{
    private:
        std::string m_sex;
    public:
        Student(const char *name = "", int age = 0, const char *sex = "female")    // 構造函數
            : Person(name, age),m_sex(sex) {}   // 清單成員初始化
        Student(const Person &p, const char *sex = "female")   // 構造函數
            : Person(p), m_sex(sex) {}  // 清單成員初始化
        int HGetAge() const
        {
            return Person::get_age();
        }
        const std::string & HGetName() const
        {
            return Person::get_name();
        }
        friend std::ostream& operator<<(std::ostream& os, const Student &stu);  // 友元函數
};

// 派生類
class Teacher : protected Person    // 保護繼承
{
    private:
        std::string m_subject;
    public:
        Teacher(const char *name, int age, const char *subject = "Chinese") // 構造函數
            : Person(name, age), m_subject(subject) {}
        Teacher(const Person & p, const char *subject = "Chinese")
            : Person(p), m_subject(subject) {}
        int HGetAge() const
        {
            return Person::get_age();
        }
        const std::string & HGetName() const
        {
            return Person::get_name();
        }
        friend std::ostream& operator<<(std::ostream& os, const Teacher &tea);  // 友元函數
};

int main()
{
    using std::cout;
    using std::endl;
    Person p1("zhangsan", 19);
    cout << p1 << endl;
    Student stu1(p1, "man");
    cout << stu1 << endl;
    
    Student stu2("lisi", 18, "female");
    // cout << "Name: " << stu2.get_name() << endl;    // 私有繼承,外界不能直接通路私有成員
    cout << "Name: " << stu2.HGetName() << endl;
    cout << "Age: " << stu2.HGetAge() << endl;
    cout << endl;
    
    Teacher t1(p1, "English");
    cout << t1 << endl;
    
    Teacher t2("wangeu", 22, "Math");
    // cout << "Name: " << t2.get_name() << endl;  // 保護繼承,外界不能直接通路保護成員
    cout << "Name: " << t2.HGetName() << endl;
    return 0;
}

std::ostream& operator<<(std::ostream &os, const Person& p)     // 友元函數
{
    os << "Name: " << p.m_name << std::endl;
    os << "Age: " << p.m_age << std::endl;
    return os;
}
std::ostream& operator<<(std::ostream& os, const Student &stu)  // 友元函數
{
    os << (Person &)stu;    // 強制類型轉換
    std::cout << "Sex: " << stu.m_sex << std::endl;
    return os;
}
std::ostream& operator<<(std::ostream& os, const Teacher &tea)  // 友元函數
{
    os << (Person &)tea;    // 強制類型轉換
    std::cout << "Subject: " << tea.m_subject << std::endl;
    return os;
}
           

程式說明

  1. Student

    類私有繼承了

    Person

    類,所有

    Person

    中的所有成員在

    Student

    中都成為了私有成員,是以外界不能直接通路基類中的公有成員。
  2. Teacher

    類保護繼承了

    Person

    類,所有

    Person

    中的保護成員和公有成員在

    Teacher

    中都成為了保護成員,但基類的私有成員在派生類中仍然為私有成員,是以外界不能直接通路基類中的公有成員。

私有繼承和保護繼承的差別

當派生類派生出另一個類時,私有繼承和保護繼承之間的主要差別就出來了。

  • 使用私有繼承時,第三代類将不能使用基類的接口,因為基類的公有方法在派生類中将變成私有方法;
  • 使用保護繼承時,基類的公有方法在第二代中變成了保護成員,是以第三代派生類可以使用他們。

使用using重新定義通路權限

使用保護繼承和私有繼承時,基類的公有成員将成為保護成員或私有成員。如果要讓基類的方法在派生類外面可用:

  1. 方法一:定義一個使用該基類方法的派生類方法。
const std::string & HGetName() const
{
    return Person::get_name();
}
           

派生類中定義了一個

HGetName()

方法來通路基類

get_name()

方法。

  1. 方法二:将函數調用包裝在另一個函數調用中,即使用一個

    using

    聲明,來指出派生類可以使用特定的基類成員。
class Student : private Person
{
    ...
    public:
        using Person::get_name;
        using Person::get_age;
    ...
};
           

using

聲明隻是用成員名———沒有圓括号、參數和傳回值。

執行個體二

#include <iostream>
#include <string>
// 基類
class Person
{
    private:    // 似有成員
        std::string m_name;   // 姓名
        int m_age;      // 年齡
    protected:   // 保護成員
        int get_age() const 
        {
            return m_age;
        }
    public:     // 公有成員
        Person(const char *name = "", int age = 0)   // 構造函數
            : m_name(name), m_age(age) {}   // 清單成員初始化
        virtual ~Person() {}  // 虛析構函數
        const std::string & get_name() const
        {
            return m_name;
        } 
        friend std::ostream& operator<<(std::ostream &os, const Person& p);     // 友元函數
};

// 派生類
class Student : private Person    // 似有繼承
{
    private:
        std::string m_sex;
    public:
        Student(const char *name = "", int age = 0, const char *sex = "female")    // 構造函數
            : Person(name, age),m_sex(sex) {}   // 清單成員初始化
        Student(const Person &p, const char *sex = "female")   // 構造函數
            : Person(p), m_sex(sex) {}  // 清單成員初始化
        using Person::get_age;      // 使用using指出get_age方法可以直接使用
        using Person::get_name;     // 用using指出get_age方法可以直接使用
        int HGetAge() const
        {
            return Person::get_age();
        }
        const std::string & HGetName() const
        {
            return Person::get_name();
        }
        friend std::ostream& operator<<(std::ostream& os, const Student &stu);  // 友元函數
};

int main()
{
    using std::cout;
    using std::endl;
    Person p1("zhangsan", 19);
    cout << p1 << endl;
    Student stu1(p1, "man");
    cout << stu1 << endl;
    
    Student stu2("lisi", 18, "female");
    cout << "Name: " << stu2.HGetName() << endl;
    cout << "Age: " << stu2.HGetAge() << endl;

    cout << "Name: " << stu2.get_name() << endl;    // 私有繼承也可以使用基類方法了
    cout << "Age: " << stu2.get_age() << endl;      // 私有繼承也可以使用基類方法了
    cout << endl;
    return 0;
}

std::ostream& operator<<(std::ostream &os, const Person& p)     // 友元函數
{
    os << "Name: " << p.m_name << std::endl;
    os << "Age: " << p.m_age << std::endl;
    return os;
}
std::ostream& operator<<(std::ostream& os, const Student &stu)  // 友元函數
{
    os << (Person &)stu;    // 強制類型轉換
    std::cout << "Sex: " << stu.m_sex << std::endl;
    return os;
}
           

程式說明

上述執行個體中使用

using

聲明使

get_age

方法和

geT_name

放在了派生類的公有成員,是以在外界也可以直接使用

get_age

方法和

get_name

了。

繼續閱讀