版本5和6间的区别
于2006-08-02 14:09:01修订的的版本5
大小: 8113
编辑: czk
备注:
于2006-08-02 15:23:11修订的的版本6
大小: 11125
编辑: czk
备注:
删除的内容标记成这样。 加入的内容标记成这样。
行号 152: 行号 152:
继承和组合是软件复用的两种方式。
行号 245: 行号 247:
类的完整实现实例:
{{{#!cplusplus
class Person {
    string name;
    bool gender;
public:
    Person(string n, bool g) : name(n), gender(g) {
    }
};
class Teacher : public Person {
    int salary;
    int level;
public:
    Teacher(string n, bool g, int s, int l) : Person(n, g), salary(s), level(l) {
    }
};
class Student: public Person {
    string id;
    int department;
public:
    Student(string n, bool g, string i, int d) : Person(n, g), id(i), department(d) {
    }
};
class GradStudent: public Student {
    Teacher *tutor;
public:
    GradStudent(string n, bool g, string i, int d, Teacher *t)
    : Student(n, g, i, d), tutor(t) {
    }
};
}}}
行号 260: 行号 293:
int main() {
    Student s;
    Person p;
}
行号 267: 行号 304:
    ~Person() { cout << "destruct Person" <<endl; }     ~Person() { cout << "destruct Person" << endl; }
行号 276: 行号 313:
}
}}}

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

派生类析构函数只负责派生类增加部分的分配资源的析构。
行号 321: 行号 359:
Student &rd = s;
Person &rp = p;
Student &rd2 = p; //error
Person &rp2 = s; // ok
行号 336: 行号 378:
在C++中允许一个派生类有多个基类,这种继承叫做多继承。相对的只有一个基类的继承被称为单继承。多继承表达的是“派生类既是一种基类A,又是一种基类B”的逻辑关系。

比如Assistent类继承了Student和Teacher两个类:
{{{#!cplusplus
class Assistant : public Student, public Teacher {
public:
  Assistant(string n, string i, string l)
 : Teacher(n, l), Student(n, i) {
    cout << "a";
  }
  void print() const {
    cout<< name << id << level; // ambiguous error
    cout<< Student::name << Teacher::name << id << level;
  }
};
}}}

多继承时对象的复制:派生类对象的指针可以赋给任何一个基类类型的指针
{{{#!cplusplus
Assistant assist("jack", "12456", "assistant");
Student s = assist; //OK, slice
Teacher t = assist; //OK, slice
Student *ps = &assist; //OK
Teacher *pt= &assist; //OK
ps->print();
pt->print();
Person *p = &assist; //ambigius
Person *p = (Student *)&assist;
Person *p = (Teacher *)&assist;
p->print();
}}}
行号 339: 行号 413:
class Person {
};
class Student : virtual public Person {
};
class Teacher : virtual public Person {
};
class Assistant : public Student, public Teacher {
};
虚基类Person在派生类Assistant的对象中只有一份

class Person {
    string name;
public:
    Person(string n):name(n){ cout << "P"; }
};
class Student : virtual public Person {
    string id;
public:
    Student(string n, string i):id(i), Person(n){ cout<<"S";}
};
class Teacher : virtual public Person {
    string level;
public:
    Teacher(string n, string l):level(l), Person(n){cout<<"T";}
};
class Assistant : public Student, public Teacher {
public:
    Assistant(string n, string i, string l)
    : Student(n, i), Teacher(n, l), Person(n) {cout<<"A";}
};
行号 340: 行号 445:
class Derived : private Base {
//…
};

class Derived: protected Base {
//…
};

class Base {
public: int a;
protected: int b;
private: int c;
};
class Derived : private Base{
    void f() {
        cout << a << b << c;
    }
};
int main() {
    Derived d;
    cout << d.a << d.b << d.c;
}

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     Student s; //派生类对象s包括了基类的全部成员,还有在派生类中新增的成员
   3     Teacher t;
   4     GradStudent grad;
   5 }

2. 派生类的访问权限

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

继承和组合是软件复用的两种方式。

3. 派生类的构造和析构

创建派生类对象时,基类的构造函数会被自动调用,用于初始化继承下来的基类部分的成员。如果派生类没有构造函数,或者没有显示调用,那么基类中的默认构造函数会被自动调用。

   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     string id;
  14 };
  15 int main() {
  16     Student d;  // default constructor of Person is called
  17 }

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

   1 class Person {
   2 public: 
   3     Person(string aname = "", bool agender = false) {
   4         name = aname;
   5         gender = agender;
   6         cout << "Person initialized" << endl;
   7     }
   8 private:
   9     string name;
  10     bool gender;
  11 };
  12 class Student : public Person{
  13     int department;
  14     string id;
  15 public:
  16     Student() :department(11), id("0509342") {
  17         cout << "Student initialized" << endl;
  18     }
  19 };
  20 int main() {
  21 }

在这个派生类的构造函数中,没有给基类的构造函数任何参数,基类中的默认构造函数会被调用。

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

   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     string name;
   3     bool gender;
   4 public:
   5     Person(string n, bool g) : name(n), gender(g) {
   6     }
   7 };
   8 class Teacher : public Person {
   9     int salary;
  10     int level;
  11 public:
  12     Teacher(string n, bool g, int s, int l) : Person(n, g), salary(s), level(l) {
  13     }
  14 };
  15 class Student: public Person {
  16     string id;
  17     int department;
  18 public:
  19     Student(string n, bool g, string i, int d) : Person(n, g), id(i), department(d) {
  20     }
  21 };
  22 class GradStudent: public Student {
  23     Teacher *tutor;
  24 public:
  25     GradStudent(string n, bool g, string i, int d, Teacher *t)
  26     : Student(n, g, i, d), tutor(t) {
  27     }
  28 };

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

   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 };
  13 int main() {
  14     Student s;
  15     Person p;
  16 }

派生类构造和析构顺序

   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     Person p;
  14 }

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

   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 }

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

有继承关系的对象复制

   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 Student &rd = s;
  10 Person &rp = p;
  11 Student &rd2 = p; //error
  12 Person &rp2 = s; // ok
  13 

指针类型的转换

   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 

5. 多继承

在C++中允许一个派生类有多个基类,这种继承叫做多继承。相对的只有一个基类的继承被称为单继承。多继承表达的是“派生类既是一种基类A,又是一种基类B”的逻辑关系。

比如Assistent类继承了Student和Teacher两个类:

   1 class Assistant : public Student, public Teacher {
   2 public:
   3   Assistant(string n, string i, string l) 
   4         :  Teacher(n, l), Student(n, i) {
   5     cout << "a";
   6   }
   7   void print() const {
   8     cout<< name << id << level; // ambiguous error
   9     cout<< Student::name << Teacher::name << id << level;
  10   }
  11 };

多继承时对象的复制:派生类对象的指针可以赋给任何一个基类类型的指针

   1 Assistant  assist("jack", "12456", "assistant");
   2 Student  s = assist; //OK, slice
   3 Teacher  t = assist; //OK, slice
   4 Student *ps = &assist; //OK
   5 Teacher *pt= &assist; //OK
   6 ps->print();
   7 pt->print();
   8 Person *p = &assist; //ambigius
   9 Person *p = (Student *)&assist;
  10 Person *p = (Teacher *)&assist;
  11 p->print();

6. 虚基类

class Person { }; class Student : virtual public Person { }; class Teacher : virtual public Person { }; class Assistant : public Student, public Teacher { }; 虚基类Person在派生类Assistant的对象中只有一份

class Person {

  • string name;

public:

  • Person(string n):name(n){ cout << "P"; }

}; class Student : virtual public Person {

  • string id;

public:

  • Student(string n, string i):id(i), Person(n){ cout<<"S";}

}; class Teacher : virtual public Person {

  • string level;

public:

  • Teacher(string n, string l):level(l), Person(n){cout<<"T";}

}; class Assistant : public Student, public Teacher { public:

  • Assistant(string n, string i, string l)

    : Student(n, i), Teacher(n, l), Person(n) {cout<<"A";}

};

7. 保护继承和私有继承

class Derived : private Base { //… };

class Derived: protected Base { //… };

class Base { public: int a; protected: int b; private: int c; }; class Derived : private Base{

  • void f() {
    • cout << a << b << c;

    }

}; int main() {

  • Derived d;

    cout << d.a << d.b << d.c;

}

8. 多态与虚函数

9. 纯虚函数和抽象类

10. 运行时类型信息

11. 面向对象设计方法

The End

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

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