c++详细学习——继承
通常讲父类(parrent)-子类(child)、基类(base)-派生类(derived)和超类(super)-子类(sub)
1 最基础的写法
以下例子为最基本的写法,默认构造
1 enum Gender { 2 MALE, 3 FEMALE, 4 }; 5 6 class Person 7 { 8 private: 9 string name; 10 Gender gend; 11 int age; 12 public: 13 Person():name(""), gend(Gender::MALE), age(18) 14 { 15 cout << "Person::Person()" << endl; 16 } 17 ~Person() 18 { 19 cout << "Person::~Person()" << endl; 20 } 21 }; 22 23 class Student : public Person 24 { 25 private: 26 int studentId; 27 int score; 28 public: 29 Student():studentId(10000), score(100) 30 { 31 cout << "Student::Student()" << endl; 32 } 33 ~Student() 34 { 35 cout << "Student::~Student()" << endl; 36 } 37 };
测试:
1 void TestAccess() 2 { 3 Student stu; 4 }
从运行结果来看,声明一个Student的对象之后,依次执行的是:Person的构造函数 --> Student的构造函数 --> Student的析构函数 --> Person的析构函数
2 访问权限
2.1 public
父类的所有public成员变量和函数都可以被子类访问、操作
Example
例子中父类Person的成员变量int age放在public中,不提供操作函数,测试函数中申明子类Student的对象后直接对age进行写和读,编译运行ok
1 enum Gender { 2 MALE, 3 FEMALE, 4 }; 5 6 class Person 7 { 8 private: 9 string name; 10 Gender gend; 11 public: 12 Person():name(""), gend(Gender::MALE), age(18) 13 { 14 cout << "Person::Person()" << endl; 15 } 16 ~Person() 17 { 18 cout << "Person::~Person()" << endl; 19 } 20 21 void SetName(const string name_) 22 { 23 name = name_; 24 } 25 string GetName() const 26 { 27 return name; 28 } 29 30 int age; 31 32 void SetGender(const Gender gend_) 33 { 34 gend = gend_; 35 } 36 Gender GetGender() const 37 { 38 return gend; 39 } 40 }; 41 42 class Student : public Person 43 { 44 private: 45 int studentId; 46 int score; 47 public: 48 Student():studentId(10000), score(100) 49 { 50 cout << "Student::Student()" << endl; 51 } 52 ~Student() 53 { 54 cout << "Student::~Student()" << endl; 55 } 56 57 void SetStudentId(const int id) 58 { 59 studentId = id; 60 } 61 int GetStudentId() const 62 { 63 return studentId; 64 } 65 66 void SetScore(const int score_) 67 { 68 score = score_; 69 } 70 int GetScore() const 71 { 72 return score; 73 } 74 };
测试函数:
1 void TestAccess() 2 { 3 Student stu; 4 stu.SetName("Tom"); 5 stu.SetGender(Gender::FEMALE); 6 stu.age = 20; /* 直接操作成员变量 */ 7 stu.SetStudentId(10001); 8 stu.SetScore(88); 9 10 cout << "name\t" << "gender\t" << "age\t" << "syudent ID\t" << "score" << endl; 11 cout << stu.GetName() << "\t" << stu.GetGender() << "\t" << stu.age << "\t" 12 << stu.GetStudentId() << "\t\t" << stu.GetScore() << endl; 13 }
运行结果ok:
2.2 private
子类拥有父类的所有private成员变量,可以通过public中父类提供的操作函数进行访问,但是没有直接操作和访问权限
Example
例子中父类Person的private成员变量int age,不提供操作函数,测试函数中申明子类Student的对象后直接对age进行写和读,编译error
1 enum Gender { 2 MALE, 3 FEMALE, 4 }; 5 6 class Person 7 { 8 private: 9 string name; 10 Gender gend; 11 int age; 12 public: 13 Person():name(""), gend(Gender::MALE), age(18) 14 { 15 cout << "Person::Person()" << endl; 16 } 17 ~Person() 18 { 19 cout << "Person::~Person()" << endl; 20 } 21 22 void SetName(const string name_) 23 { 24 name = name_; 25 } 26 string GetName() const 27 { 28 return name; 29 } 30 31 void SetGender(const Gender gend_) 32 { 33 gend = gend_; 34 } 35 Gender GetGender() const 36 { 37 return gend; 38 } 39 }; 40 41 class Student : public Person 42 { 43 private: 44 int studentId; 45 int score; 46 public: 47 Student():studentId(10000), score(100) 48 { 49 cout << "Student::Student()" << endl; 50 } 51 ~Student() 52 { 53 cout << "Student::~Student()" << endl; 54 } 55 56 void SetStudentId(const int id) 57 { 58 studentId = id; 59 } 60 int GetStudentId() const 61 { 62 return studentId; 63 } 64 65 void SetScore(const int score_) 66 { 67 score = score_; 68 } 69 int GetScore() const 70 { 71 return score; 72 } 73 };
测试函数:
1 void TestAccess() 2 { 3 Student stu; 4 stu.SetName("Tom"); 5 stu.SetGender(Gender::FEMALE); 6 stu.age = 20; /* 直接操作成员变量 */ 7 stu.SetStudentId(10001); 8 stu.SetScore(88); 9 10 cout << "name\t" << "gender\t" << "age\t" << "syudent ID\t" << "score" << endl; 11 cout << stu.GetName() << "\t" << stu.GetGender() << "\t" << stu.age << "\t" 12 << stu.GetStudentId() << "\t\t" << stu.GetScore() << endl; 13 }
编译结果error
2.3 protected
父类protected成员变量和函数,子类可以当父类的private变量使用,但父类的对象不能不能使用
Example
例子中父类Person的protected成员函数PrintBaseInfo(),测试函数中Person的对象直接使用,编译error。但子类Student可以把它当父类的private成员函数一样使用。
1 enum Gender { 2 MALE, 3 FEMALE, 4 }; 5 6 class Person 7 { 8 private: 9 string name; 10 Gender gend; 11 int age; 12 protected: 13 void PrintBaseInfo() 14 { 15 cout << "Person::PrintBaseInfo()\t"; 16 cout << "name: " << name << "\tgend: " << gend << "\tage: " << age << endl; 17 } 18 public: 19 Person():name(""), gend(Gender::MALE), age(18) 20 { 21 cout << "Person::Person()" << endl; 22 } 23 ~Person() 24 { 25 cout << "Person::~Person()" << endl; 26 } 27 28 void SetName(const string name_) 29 { 30 name = name_; 31 } 32 string GetName() const 33 { 34 return name; 35 } 36 37 void SetGender(const Gender gend_) 38 { 39 gend = gend_; 40 } 41 Gender GetGender() const 42 { 43 return gend; 44 } 45 46 void SetAge(const int age_) 47 { 48 age = age_; 49 } 50 int GetAge() const 51 { 52 return age; 53 } 54 }; 55 56 class Student : public Person 57 { 58 private: 59 int studentId; 60 int score; 61 public: 62 Student():studentId(10000), score(100) 63 { 64 cout << "Student::Student()" << endl; 65 } 66 ~Student() 67 { 68 cout << "Student::~Student()" << endl; 69 } 70 71 void SetStudentId(const int id) 72 { 73 studentId = id; 74 } 75 int GetStudentId() const 76 { 77 return studentId; 78 } 79 80 void SetScore(const int score_) 81 { 82 score = score_; 83 } 84 int GetScore() const 85 { 86 return score; 87 } 88 89 void Print() 90 { 91 PrintBaseInfo(); /* 子类使用父类的protected成员函数, ok */ 92 } 93 };
测试函数:
1 void TestAccess() 2 { 3 Person per; 4 // per.PrintBaseInfo(); /* error */ 5 6 Student stu; 7 stu.SetName("Tom"); 8 stu.SetGender(Gender::FEMALE); 9 stu.SetAge(24); 10 stu.SetStudentId(10001); 11 stu.SetScore(88); 12 stu.Print(); 13 14 cout << "name\t" << "gender\t" << "age\t" << "syudent ID\t" << "score" << endl; 15 cout << stu.GetName() << "\t" << stu.GetGender() << "\t" << stu.GetAge() << "\t" 16 << stu.GetStudentId() << "\t\t" << stu.GetScore() << endl; 17 }
执行结果:
3 构造和析构
在第1章中已经介绍,依次执行的是:Person的构造函数 --> Student的构造函数 --> Student的析构函数 --> Person的析构函数
子类对父类的初始化必须放在子类构造函数的初始化列表中,这是初始化父类的唯一办法
1 enum Gender { 2 MALE, 3 FEMALE, 4 }; 5 6 class Person 7 { 8 private: 9 string name; 10 Gender gend; 11 int age; 12 public: 13 Person(const string &_name, const Gender _gend, const int _age) : name(_name), gend(_gend), age(_age) 14 { 15 cout << "Person::Person()" << endl; 16 } 17 ~Person() 18 { 19 cout << "Person::~Person()" << endl; 20 } 21 }; 22 23 class Student : public Person 24 { 25 private: 26 int studentId; 27 int score; 28 public: 29 Student(const int id, const int _score) : Person("", Gender::MALE, 18), studentId(id), score(_score) 30 { 31 cout << "Student::Student()" << endl; 32 } 33 ~Student() 34 { 35 cout << "Student::~Student()" << endl; 36 } 37 };
4 继承与重载
4.1 重载(overload)
在类中有多个函数类型和函数名相同,但参数列表不同的成员函数时,各个同名的函数之间形成重载,调用时根据调用者的参数去匹配这些重载函数
Example
Person类中4个Print之间构成重载的关系,Person的对象调用时根据传的实参参数类型或个数不同,执行不同的Print()。
1 enum Gender { 2 MALE, 3 FEMALE, 4 }; 5 6 class Person 7 { 8 private: 9 string name; 10 Gender gend; 11 int age; 12 public: 13 Person(const string &_name, const Gender _gend, const int _age) : name(_name), gend(_gend), age(_age) 14 { 15 cout << "Person::Person()" << endl; 16 } 17 ~Person() 18 { 19 cout << "Person::~Person()" << endl; 20 } 21 22 void Print() 23 { 24 cout << "Person::Print 1" << endl; 25 } 26 void Print(const int num) 27 { 28 cout << "Person::Print 2" << endl; 29 } 30 void Print(const string str) 31 { 32 cout << "Person::Print 3" << endl; 33 } 34 void Print(const int num1, const int num2) 35 { 36 cout << "Person::Print 4" << endl; 37 } 38 };
测试函数:
1 void TestAccess() 2 { 3 Person per("", Gender::MALE, 18); 4 per.Print(); 5 per.Print(100); 6 per.Print("hello"); 7 per.Print(100, 300); 8 }
测试结果:
4.2 继承与重载
(1)子类中没有与父类重载函数同名的成员函数
子类中没有与父类重载函数同名的成员函数时,子类依然可以根据传递的参数类型不同或个数不同,调用到父类不同的函数
Example
父类Person中4个Print()之间构成重载的关系,子类Student的对象调用Print()时,根据传的实参参数类型或个数不同,执行父类不同的Print()。
1 enum Gender { 2 MALE, 3 FEMALE, 4 }; 5 6 class Person 7 { 8 private: 9 string name; 10 Gender gend; 11 int age; 12 public: 13 Person(const string &_name, const Gender _gend, const int _age) : name(_name), gend(_gend), age(_age) 14 { 15 cout << "Person::Person()" << endl; 16 } 17 ~Person() 18 { 19 cout << "Person::~Person()" << endl; 20 } 21 22 void Print() 23 { 24 cout << "Person::Print 1" << endl; 25 } 26 void Print(const int num) 27 { 28 cout << "Person::Print 2" << endl; 29 } 30 void Print(const string str) 31 { 32 cout << "Person::Print 3" << endl; 33 } 34 void Print(const int num1, const int num2) 35 { 36 cout << "Person::Print 4" << endl; 37 } 38 }; 39 40 class Student : public Person 41 { 42 private: 43 int studentId; 44 int score; 45 public: 46 Student(const int id, const int _score) : Person("", Gender::MALE, 18), studentId(id), score(_score) 47 { 48 cout << "Student::Student()" << endl; 49 } 50 ~Student() 51 { 52 cout << "Student::~Student()" << endl; 53 } 54 };
测试函数:
1 void TestAccess() 2 { 3 Student stu(10001, 100); 4 5 stu.Print(); 6 stu.Print(100); 7 stu.Print("hello"); 8 stu.Print(100, 300); 9 }
测试结果:
(2)子类中存在与父类重载函数同名的成员函数
子类中存在与父类重载函数相同函数名的成员函数时,子类的该函数与父类的重载函数没有关系,此在OOP语言中是C++独有的,称之为名字隐藏(name hidden)
Example
子类中也有Print()函数,此时子类的Print()把父类的Print()隐藏掉了
1 enum Gender { 2 MALE, 3 FEMALE, 4 }; 5 6 class Person 7 { 8 private: 9 string name; 10 Gender gend; 11 int age; 12 public: 13 Person(const string &_name, const Gender _gend, const int _age) : name(_name), gend(_gend), age(_age) 14 { 15 cout << "Person::Person()" << endl; 16 } 17 ~Person() 18 { 19 cout << "Person::~Person()" << endl; 20 } 21 22 void Print() 23 { 24 cout << "Person::Print 1" << endl; 25 } 26 void Print(const int num) 27 { 28 cout << "Person::Print 2" << endl; 29 } 30 void Print(const string str) 31 { 32 cout << "Person::Print 3" << endl; 33 } 34 void Print(const int num1, const int num2) 35 { 36 cout << "Person::Print 4" << endl; 37 } 38 }; 39 40 class Student : public Person 41 { 42 private: 43 int studentId; 44 int score; 45 public: 46 Student(const int id, const int _score) : Person("", Gender::MALE, 18), studentId(id), score(_score) 47 { 48 cout << "Student::Student()" << endl; 49 } 50 ~Student() 51 { 52 cout << "Student::~Student()" << endl; 53 } 54 55 void Print() 56 { 57 cout << "Student::Print()" << endl; 58 } 59 };
测试函数:
1 void TestAccess() 2 { 3 Student stu(10001, 100); 4 5 stu.Print(); 6 // stu.Print(100); /* 编译error */ 7 // stu.Print("hello"); /* 编译error */ 8 // stu.Print(100, 300); /* 编译error */ 9 }
测试结果: