class 子類名 : public 父類名 { }; /* 示例 */ class Person { }; // Student繼承自Person class Student : public Person { };
一個類對象的內存空間 = 全部成員變量所佔空間的總和ios
一個子類對象的內存空間 = 全部父類成員變量所佔空間的總和 + 自身成員變量所佔空間的總和ide
對象所佔空間不包含靜態成員變量函數
子類中,父類成員變量在內存中的位置靠前測試
類中存在虛函數時,會多出一個指針的空間存放虛函數表的地址,而這個指針位於對象開頭this
#include <iostream> using namespace std; class Person { int age; }; class Student : public Person { int id; }; int main() { cout << sizeof(Student) << endl; // 8,兩個int cout << sizeof(Person) << endl; // 4,1個int return 0; }
採用初始化列表spa
#include <iostream> using namespace std; class Person { public: int age; Person(int age) : age(age) { } }; class Student : public Person { public: int id; Student(int id, int age) : Person(age), id(id) { } }; int main() { Student student(1, 25); cout << student.id << endl; cout << student.age << endl; return 0; }
建立:父類 -> 子類
消亡:子類 -> 父類指針
#include <iostream> using namespace std; class Person { public: Person() { cout << "Person()" << endl; } ~Person() { cout << "~Person()" << endl; } }; class Student : public Person { public: Student() { cout << "Student()" << endl; } ~Student() { cout << "~Student()" << endl; } }; int main() { Student student; return 0; }
父類名::方法名();code
#include <iostream> using namespace std; class Person { public: int age; void sayHello() { cout << "Hello" << endl; } }; class Student : public Person { public: int id; void sayHello() { Person::sayHello(); cout << "World" << endl; } }; int main() { Student student; student.sayHello(); return 0; }
多態就是父類的指針或引用調用子類的方法或變量對象
#include <iostream> using namespace std; class Person { public: void sayHi() { cout << "Person sayHi" << endl; } }; class Student : public Person { public: void sayHi() { cout << "Student sayHi" << endl; } }; int main() { Student student; Person * pPerson = &student; pPerson->sayHi(); // 打印:Person sayHi Person & rPerson = student; rPerson.sayHi(); // 打印:Person sayHi return 0; }
滿心期待上面的代碼可以完成多態,結果...尼瑪怎麼不對!!!繼承
原來坑爹C++又整出個虛函數
一個正常的成員函數前加virtual關鍵字
若是該方法在父類中已經定義爲虛函數,那麼子類virtual能夠省略,但不建議
#include <iostream> using namespace std; class Person { public: void sayHi() { cout << "Person sayHi" << endl; } virtual void sayHello() { cout << "Person sayHello" << endl; } }; class Student : public Person { public: void sayHi() { cout << "Student sayHi" << endl; } void sayHello() { cout << "Student sayHello" << endl; } }; int main() { Student student; Person * pPerson = &student; pPerson->sayHi(); pPerson->sayHello(); // 引用方式調用多態 // Person & rPerson = student; // rPerson.sayHi(); // rPerson.sayHello(); return 0; }
構造函數和析構函數中,能夠調用虛函數,但不會出現多態。緣由是父類構造函數調用時,子類成員變量還未初始化,父類析構函數調用時,子類析構函數已經執行完畢。總之若是能夠在構造和析構函數中出現多態,是危險的。
#include <iostream> using namespace std; class Person { public: Person() { sayHello(); } virtual void sayHello() { cout << "Person sayHello" << endl; } // 析構函數測試 // ~Person() { // sayHello(); // } }; class Student : public Person { public: Student() { sayHello(); } virtual void sayHello() { cout << "Student sayHello" << endl; } // ~Student() { // sayHello(); // } }; int main() { Student student; return 0; }
當父類指針或引用調用不是虛函數的成員函數,這個成員函數中又調用了虛函數,會出現多態。
#include <iostream> using namespace std; class Person { public: void sayHi() { cout << "Person sayHi" << endl; sayHello(); // 至關於this->sayHello(); 跟在外部用指針調用是一個意思 } virtual void sayHello() { cout << "Person sayHello" << endl; } }; class Student : public Person { public: void sayHi() { cout << "Student sayHi" << endl; sayHello(); } virtual void sayHello() { cout << "Student sayHello" << endl; } }; int main() { Student student; Person * pPerson = &student; pPerson->sayHi(); return 0; }
多態實現的關鍵是虛函數表
每個有虛函數的類(或是父類中有虛函數) 都有一個虛函數表
該類的對象在內存的開頭,存放着一個指針,這個指針指向虛函數表
虛函數表中列出了該類的虛函數地址
#include <iostream> using namespace std; class Person { public: virtual void sayHello() { } }; int main() { // 跟一個指針的大小是同樣的 cout << sizeof(Person) << endl; return 0; }
當用父類指針或引用,delete時,只有父類的析構函數會被調用。定義虛析構函數能夠解決這個問題。
#include <iostream> using namespace std; class Person { public: ~Person() { cout << "~Person" << endl; } }; class Student : public Person { public: ~Student() { cout << "~Student" << endl; } }; int main() { Person * person = new Student; delete person; return 0; }
在析構函數前加virtual關鍵字
若是父類的析構函數已經加了virtual,子類中的virtual關鍵字能夠省略,不推薦
#include <iostream> using namespace std; class Person { public: Person() { cout << "Person" << endl; } virtual ~Person() { cout << "~Person" << endl; } }; class Student : public Person { public: Student() { cout << "Student" << endl; } ~Student() { cout << "~Student" << endl; } }; int main() { Person * person = new Student; delete person; return 0; }
純虛函數: 沒有函數體的虛函數
抽象類: 包含純虛函數的類
非抽象類: 實現全部純虛函數的類
virtual 返回值 函數名(參數列表) = 0 ;
#include <iostream> using namespace std; class CGeometry { public: virtual ~CGeometry(){ } virtual double calPerimeter() = 0; }; class CTriangle : public CGeometry { public: double side1; double side2; double side3; virtual double calPerimeter() { return side1 + side2 + side3; } }; class CCircle : public CGeometry { public: double radius; virtual double calPerimeter() { return 2 * 3.14 * radius; } }; class CRectangle : public CGeometry { public: double width; double height; virtual double calPerimeter() { return 2 * (width + height); } }; int compare(const void * p1, const void * p2) { int result = 0; CGeometry ** g1 = (CGeometry **)p1; CGeometry ** g2 = (CGeometry **)p2; double perimeter1 = (*g1)->calPerimeter(); double perimeter2 = (*g2)->calPerimeter(); if (perimeter1 > perimeter2) { result = 1; } else if (perimeter1 < perimeter2) { result = -1; } return result; } /* 運行:前四行爲輸入,後3行爲輸出 3 R 1 1 C 1 T 1 1 1 3 4 6.28 */ int main() { int number; cin >> number; char type; CGeometry * geometries[number]; CTriangle * pTriangle; CCircle * pCircle; CRectangle * pRectangle; for (int i = 0; i < number; i++) { cin >> type; switch (type) { case 'R': pRectangle = new CRectangle(); cin >> pRectangle->width >> pRectangle->height; geometries[i] = pRectangle; break; case 'C': pCircle = new CCircle(); cin >> pCircle->radius; geometries[i] = pCircle; break; case 'T': pTriangle = new CTriangle(); cin >> pTriangle->side1 >> pTriangle->side2 >> pTriangle->side3; geometries[i] = pTriangle; break; } } qsort(geometries, number, sizeof(CGeometry *), compare); for (int i = 0; i < number; i++) { cout << geometries[i]->calPerimeter() << endl; delete geometries[i]; } return 0; }