版本1和2间的区别
于2006-06-26 19:51:23修订的的版本1
大小: 6932
编辑: czk
备注:
于2006-06-26 23:44:45修订的的版本2
大小: 7173
编辑: czk
备注:
删除的内容标记成这样。 加入的内容标记成这样。
行号 5: 行号 5:
利用已有的类,进行扩充构成新类的机制
基类/父类
派生类/子类
基类和派生类是一种is a的关系
在已有的类的基础上,添加新的成员进行扩充,构成新类的机制称为派生/继承。已有的类称为基类/父类,扩充形成的新类称为派生类/子类。派生类和基类是一种is a的关系。比如说,学生Student是一类人Person,老师Teacher也是一类人Person,研究生GraduateStudent是一类学生Student。
行号 27: 行号 24:
 string ID;
 int department;
    string ID;
    int department;
行号 32: 行号 29:
 Teacher *tutor;     Teacher *tutor;

继承

1. 派生类的定义

在已有的类的基础上,添加新的成员进行扩充,构成新类的机制称为派生/继承。已有的类称为基类/父类,扩充形成的新类称为派生类/子类。派生类和基类是一种is a的关系。比如说,学生Student是一类人Person,老师Teacher也是一类人Person,研究生GraduateStudent是一类学生Student。

   1 class Person {
   2 private:
   3     string name;
   4     Date birth;
   5     bool gender;
   6 };
   7 class Teacher : public Person 
   8 {
   9 private:
  10     int salary;
  11     int level;
  12 };
  13 
  14 class Student : public Person 
  15 {
  16 private:
  17     string ID;
  18     int department;
  19 };
  20 class GradStudent : public Student {
  21 private:
  22     Teacher *tutor;
  23 };

成员函数实现

   1 class Person {
   2     string name;
   3     Date birth;
   4     bool gender;
   5 public:
   6     string get_name();
   7     Date get_date();
   8     bool get_gender();
   9 };
  10 class Teacher : public Person {
  11     int salary;
  12     int level;
  13 public:
  14     int get_salary();
  15     int get_level();
  16 };
  17 class Student: public Person {
  18     string ID;
  19     int department;
  20 public:
  21     string get_id();
  22     int get_department();
  23 };
  24 class GradStudent: public Student {
  25     Teacher *tutor;
  26 public:
  27     Teacher *get_tutor();
  28 };

派生类的访问权限

  • private成员:只在本类中可以访问,在派生类中不可访问的成员。基类的私有成员被派生类继承,但是不能被派生类访问
  • protected成员:在本类及派生类中能访问的成员。派生类可以访问继承的保护成员,但是不能访问一个基类对象的保护成员

   1 class Base {
   2     public: int a;
   3     protected: int b;
   4     private: int c;
   5 };
   6 class Derived :public Base {
   7     void f() {
   8         cout << a << b << c;
   9     }
  10 };
  11 void f(Derived &d) {
  12     cout << d.a<< d.b<< d.c;
  13 }

   1 class Base {
   2 protected:
   3     int x;
   4 };
   5 class Derived  : public Base{
   6 public:
   7     void f( ) {
   8         Base b;
   9         cout << b.x;
  10         cout << x;
  11     }
  12 };

使用using声明改变基类成员权限

   1 class Person {
   2 public:
   3     string get_name();
   4     Date get_date();
   5     bool get_gender();
   6 };
   7 class Student : public Person {
   8 private:
   9     using Person::get_name;
  10 };

派生类的成员名字如果与基类相同,将隐藏基类成员

   1 class Person {
   2 public:
   3     void set(string name);
   4     void set(bool gender);
   5 };
   6 class Student : public Person{
   7 public:
   8     void set(int department); // hide base member functions
   9 };
  10 void f(Student &s) {
  11     s.set("12345"); 
  12     s.set( true );
  13     s.Person::set("12345"); //ok
  14     s.Person::set(true); //ok
  15 }

2. 派生类的构造和析构

创建派生类对象时,基类的构造函数会被自动调用。如果派生类没有构造函数,或者没有显示调用,那么基类中的默认构造函数会被自动调用。

   1 class Person {
   2 public: 
   3     Person(string aname = "", bool agender = false) { 
   4         name = aname; gender = agender;
   5     }
   6 private:
   7     string name;
   8     bool gender;
   9 };
  10 class Student : public Person {
  11 private:
  12     int department;
  13 };
  14 int main() {
  15     Student d;  // default constructor of Person is called
  16 }

派生类可以定义自己的构造函数,用于初始化派生类扩展的部分

   1 class Person {
   2 public: 
   3     Person(string aname = "", bool agender = false) {
   4         name = aname;
   5         gender = agender;
   6     }
   7 private:
   8     string name;
   9     bool gender;
  10 };
  11 class Student : public Person{
  12 public:
  13     Student(int dep) {
  14         department = dep;
  15     }
  16 private:
  17     int department;
  18 };

如果基类的构造函数需要参数,那么需要使用初始化列表为基类构造提供参数。

   1 class Person {
   2 public: 
   3     Person(string aname, bool agender) {
   4         name = aname;
   5         gender = agender;
   6     }
   7 private:
   8     string name;
   9     bool gender;
  10 };
  11 class Student : public Person {
  12 public:
  13     Student(string name, bool gender, int dep) 
  14         : department(dep) , Person ( name, gender )
  15     {
  16     }
  17 private:
  18     int department;
  19 };

创建一个派生类对象时,必须显式或者隐式的调用基类的构造函数。在一个多层的继承结构里面,创建一个派生类对象时,所有的基类的构造函数都会被调用。

   1 class Person {
   2 public: 
   3     Person( ) { cout << "construct Person"; }
   4 };
   5 class Student : public Person {
   6 public:
   7     Student( ) { cout << "construct Student"; }
   8 };
   9 class GradStudent : public Student {
  10 public:
  11     GradStudent( ) { cout << "construct GradStudent"; }
  12 };
  13 int main( ) {
  14     GradStudent gs;
  15 }

派生类对象被销毁时,基类的析构函数会被自动调用。如果派生类和基类都有析构函数,那么他们都会被调用。

   1 class Person {
   2 public: 
   3     ~Person() { 
   4         cout <<"destruct Person" <<endl;
   5     }
   6 };
   7 class Student : public Person{
   8 public:
   9     ~Student() {
  10         cout << "destruct Student" << endl;
  11     }
  12 };

派生类构造和析构顺序

   1 class Person {
   2 public: 
   3     Person() { cout << "construct Person" << endl; } 
   4     ~Person() { cout << "destruct Person" <<endl; }
   5 };
   6 class Student : public Person{
   7 public:
   8     Student() { cout << "construct Student" <<endl; }
   9     ~Student() { cout << "destruct Student" <<endl; }
  10 };
  11 int main() {
  12     Student s;
  13 }

派生类的构造析构实例。派生类析构函数只负责派生类增加部分的分配资源的析构。

   1 class Base {
   2 public: 
   3     Base() { 
   4         s = new char[3];
   5     }
   6     ~Base() {
   7         delete[ ] s;
   8     }
   9 private:
  10     char *s;
  11 };
  12 class Derived : public Base {
  13 public: 
  14     Derived() { 
  15         sd = new char[5]; 
  16     }
  17     ~Derived () {
  18         delete[ ] sd;
  19     }
  20 private:
  21     char *sd;
  22 };
  23 int main() {
  24     Base b;
  25     Derived  d;
  26 }

3. 派生类对象和对象指针的复制

有继承关系的对象复制

   1 Student s("jack", Date(1980, 8, 8), true, 970101, 10);
   2 Person  p = s; //slice
   3 Student  s = p; //error
   4 
   5 Student  *pD = new Student("jack", Date(1980, 8, 8), true, 970101, 10);
   6 Person *pB = pD;  //correct 基类指针指向派生类对象
   7 Person *pB2 = new Student("jack", Date(1980, 8, 8), true, 970101, 10);
   8 pB = new Teacher; //多态性在这里体现
   9 

指针类型的转换

   1 Person  *pB = new Student;
   2 Student *pD2 = pB; //error
   3 Student *pD3 = dynamic_cast<Student *>(pB);
   4 
   5 Person *pB = new Teacher;
   6 Student *pD = dynamic_cast<Student *>(pB); //转换失败,得到空指针
   7 Student *pD2 = static_cast<Student *>(pB); //static_cast转换时不做检查,访问pD2的后果不堪设想
   8 pD2->get_id(); //不可设想的后果
   9 

4. 多继承

5. 虚基类

6. 保护继承和私有继承

7. 多态与虚函数

8. 纯虚函数和抽象类

9. 运行时类型信息

10. 面向对象设计方法

The End

C++继承与多态 (2008-02-23 15:35:15由localhost编辑)

ch3n2k.com | Copyright (c) 2004-2020 czk.