版本3和4间的区别
于2006-06-26 23:45:52修订的的版本3
大小: 7194
编辑: czk
备注:
于2006-08-02 13:31:54修订的的版本4
大小: 7808
编辑: czk
备注:
删除的内容标记成这样。 加入的内容标记成这样。
行号 1: 行号 1:
[[TableOfContents]]
行号 2: 行号 4:
[[TableOfContents]]
行号 6: 行号 7:
在已有的类的基础上,添加新的成员进行扩充,构成新类的机制称为派生/继承。已有的类称为基类/父类,扩充形成的新类称为派生类/子类。派生类和基类是一种is a的关系。比如说,学生Student是一类人Person,老师Teacher也是一类人Person,研究生GraduateStudent是一类学生Student。 继承/派生是类的重用的一种方法。继承/派生是指在已有的类的基础上,添加新的成员进行扩充,构成新类的机制。已有的类称为基类/父类,扩充形成的新类称为派生类/子类。父类派生出子类,子类继承了父类。派生类和基类在逻辑生存在is a的关系。比如说,学生Student是一类人Person,老师Teacher也是一类人Person,研究生GraduateStudent是一类学生Student。我们用C++语言来描述这种关系:
行号 15: 行号 16:

//Teacher类继承了Person类
行号 21: 行号 24:
//Student类继承了Person类,public指明继承方式是公有继承
行号 28: 行号 31:
//GradStudent类继承了Student类
行号 34: 行号 38:
成员函数实现 加上成员函数实现
行号 66: 行号 70:
派生类对象的定义:
{{{#!cplusplus
int main() {
    Person p;
    Student s;
    Teacher t;
    GradStudent grad;
}
}}}
行号 68: 行号 82:
 * private成员:只在类中可以访问,在派生类中不可访问的成员。基类的私有成员被派生类继承,但是不能被派生类访问  * private成员:只在定义它的的成员函数中可以访问,在派生类的成员函数中不可访问。基类的私有成员被派生类继承,但是不能被派生类访问
行号 73: 行号 87:
    public: int a;
    protected: int b;
    private: int c;
public:
   
int a;
protected:
   
int b;
private:
   
int c;
行号 79: 行号 96:
        cout << a << b << c;         cout << a << b << c;//访问c是错误的
行号 83: 行号 100:
    cout << d.a<< d.b<< d.c;     cout << d.a<< d.b<< d.c; //访问b,c都是错的
行号 96: 行号 113:
        Base b;
        cout << b.x;
        cout << x;
        Base b; 
        cout << b.x; //访问基类对象的保护成员,错误
        cout << x;  //发访问继承的基类保护成员,正确

TableOfContents

继承

1. 派生类的定义

继承/派生是类的重用的一种方法。继承/派生是指在已有的类的基础上,添加新的成员进行扩充,构成新类的机制。已有的类称为基类/父类,扩充形成的新类称为派生类/子类。父类派生出子类,子类继承了父类。派生类和基类在逻辑生存在is a的关系。比如说,学生Student是一类人Person,老师Teacher也是一类人Person,研究生GraduateStudent是一类学生Student。我们用C++语言来描述这种关系:

   1 class Person {
   2 private:
   3     string name;
   4     Date birth;
   5     bool gender;
   6 };
   7 
   8 //Teacher类继承了Person类
   9 class Teacher : public Person 
  10 {
  11 private:
  12     int salary;
  13     int level;
  14 };
  15 //Student类继承了Person类,public指明继承方式是公有继承
  16 class Student : public Person 
  17 {
  18 private:
  19     string ID;
  20     int department;
  21 };
  22 //GradStudent类继承了Student类
  23 class GradStudent : public Student {
  24 private:
  25     Teacher *tutor;
  26 };

加上成员函数的实现:

   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 };

派生类对象的定义:

   1 int main() {
   2     Person p;
   3     Student s;
   4     Teacher t;
   5     GradStudent grad;
   6 }

派生类的访问权限

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

   1 class Base {
   2 public:
   3     int a;
   4 protected:
   5     int b;
   6 private:
   7     int c;
   8 };
   9 class Derived :public Base {
  10     void f() {
  11         cout << a << b << c;//访问c是错误的
  12     }
  13 };
  14 void f(Derived &d) {
  15     cout << d.a<< d.b<< d.c; //访问b,c都是错的
  16 }

   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.