私有繼承
使用私有繼承,基類的公有成員和保護成員都将成為派生類的私有成員。
使用私有繼承意味着基類方法将不能在外部直接使用,但可以在派生類的成員函數中使用他們。
保護繼承
使用保護繼承,基類的公有成員和保護成員都将成為派生類的保護成員。
使用保護繼承意味着基類方法将不能在外部直接使用,但可以在派生類的成員函數中使用他們。
執行個體一
#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;
}
程式說明
-
類私有繼承了Student
類,所有Person
中的所有成員在Person
中都成為了私有成員,是以外界不能直接通路基類中的公有成員。Student
-
類保護繼承了Teacher
類,所有Person
中的保護成員和公有成員在Person
中都成為了保護成員,但基類的私有成員在派生類中仍然為私有成員,是以外界不能直接通路基類中的公有成員。Teacher
私有繼承和保護繼承的差別
當派生類派生出另一個類時,私有繼承和保護繼承之間的主要差別就出來了。
- 使用私有繼承時,第三代類将不能使用基類的接口,因為基類的公有方法在派生類中将變成私有方法;
- 使用保護繼承時,基類的公有方法在第二代中變成了保護成員,是以第三代派生類可以使用他們。
使用using重新定義通路權限
使用保護繼承和私有繼承時,基類的公有成員将成為保護成員或私有成員。如果要讓基類的方法在派生類外面可用:
- 方法一:定義一個使用該基類方法的派生類方法。
const std::string & HGetName() const
{
return Person::get_name();
}
派生類中定義了一個
HGetName()
方法來通路基類
get_name()
方法。
- 方法二:将函數調用包裝在另一個函數調用中,即使用一個
聲明,來指出派生類可以使用特定的基類成員。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
了。