私有继承
使用私有继承,基类的公有成员和保护成员都将成为派生类的私有成员。
使用私有继承意味着基类方法将不能在外部直接使用,但可以在派生类的成员函数中使用他们。
保护继承
使用保护继承,基类的公有成员和保护成员都将成为派生类的保护成员。
使用保护继承意味着基类方法将不能在外部直接使用,但可以在派生类的成员函数中使用他们。
实例一
#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
了。