父类指针与子类指针,开发中经常用到(继承方式必须是public,否则父类指针是不能指向子类对象的,编译器会报错)
class Person {
public:
int m_age;
};
class Student : public Person {
public:
int m_score;
};
父类指针可以指向子类对象,这样是安全的
子类指针不可以指向父类对象,这样是不安全的 ```swift int main() { // 学生是一个人(编译通过) Person *stu = new Student(); stu->m_age = 10;
// 如果不强制转换(Student *),编译器都不会通过
// 这样是不安全的,因为父类对象只占用4个字节
Student *p = (Student *) new Person();
p->m_age = 10;
p->m_score = 20;
getchar();
return 0; } ``` # 面向对象的3大特性: - 封装 - 继承 - 多态
多态
默认情况下,编译器只会根据指针类型调用对应的函数,不存在多态
多态是面向对象非常重要的一个特性
同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果
在运行时,可以识别出真正的对象类型,调用对应子类中的函数
多态的要素
- 子类重写父类的成员函数(override)
- 父类指针指向子类对象
- 利用父类指针调用重写的成员函数
默认情况,父类成员函数run()
不加virtual
class Animal {
public:
// virtual
void run() {
cout << "Animal::run()" << endl;
}
};
class Cat : public Animal {
public:
void run() {
cout << "Cat::run()" << endl;
}
};
class Dog : public Animal {
public:
void run() {
cout << "Dog::run()" << endl;
}
};
class Pig : public Animal {
public:
void run() {
cout << "Pig::run()" << endl;
}
};
int main() {
Animal *animal = new Pig();
// 打印是"Animal::run()"而不是"Pig::run()"
animal->run();
getchar();
return 0;
}
默认以上写法,打印是”Animal::run()”而不是”Pig::run()”,这是编译器的特性,指针是什么类型,就会调用指针对象的某个方法
如果想实现多态,执行真正对象的某个方法,只需要将父类的成员函数前加virtual
关键字,子类成员函数前virtual
可以省略,也可以写上
如果继承关系如下ErHa-> Dog->Animal,关键字virtual
只在Dog的成员函数前面有
class Animal {
public:
void run() {
cout << "Animal::run()" << endl;
}
};
class Dog : public Animal {
public:
virtual void run() {
cout << "Dog::run()" << endl;
}
};
class ErHa : public Dog {
public:
void run() {
cout << "ErHa::run()" << endl;
}
};
那么,所有Animal修饰的指针,只会调用Animal的成员函数 以Dog开始,才会实现多态
int main() {
Animal *animal0 = new Animal();
animal0->run(); // "Animal::run()"
Animal *animal1 = new Dog();
animal1->run(); // "Animal::run()"
Animal *animal2 = new ErHa();
animal2->run(); // "Animal::run()"
Dog *dog0 = new Dog();
dog0->run(); // "Dog::run()"
// 多态要素:
// 1.子类重写父类的成员函数(override)
// 2.父类指针指向子类对象
// 3.利用父类指针调用重写的成员函数
Dog *dog1 = new ErHa();
dog1->run(); // "ErHa::run()"
getchar();
return 0;
}
虚函数
- C++中的多态通过虚函数(virtual function)来实现
- 虚函数:被
virtual
修饰的成员函数 - 只要在父类中声明为虚函数,子类中重写的函数也自动变成虚函数(也就是说子类中可以省略
virtual
关键字)
知识点回顾:
重写:子类重写(覆盖)父类的方法 重载: 同一个类里面,同一个方法参数顺序或者个数不同