继承
语法
class 子类名 : public 父类名 {
};
/* 示例 */
class Person {
};
// Student继承自Person
class Student : public Person {
};
子类对象的内存空间
一个类对象的内存空间 = 所有成员变量所占空间的总和
一个子类对象的内存空间 = 所有父类成员变量所占空间的总和 + 自身成员变量所占空间的总和
对象所占空间不包含静态成员变量
子类中,父类成员变量在内存中的位置靠前
类中存在虚函数时,会多出一个指针的空间存放虚函数表的地址,而这个指针位于对象开头
#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;
}
调用父类构造方法
采用初始化列表
#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;
}
重载时调用父类方法
父类名::方法名();
#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;
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。