多态
说的就是不同的对象收到相同的任务输出不同的结果。
静态多态
#include <iostream>
int sum(int a, int b) {
return a + b;
}
double sum(double a, double b) {
return a + b;
}
int main() {
std::cout << sum(1,2) << std::endl;
std::cout << sum(3.3, 2.9) << std::endl;
return 0;
}
可以看到上述有两种sum函数,其中第一个为算两个整形数的和,第二个算小数的和。
静态多态就是在编译过程中,编译器会根据函数的类型、参数等情况来辨别应该使用哪个函数。
值得注意的是重载函数的返回值和参数是跟被重载的函数返回类型与参数类型不同的。
动态多态
#include <iostream>
class A {
public:
A() {}
void print() { std::cout << "A" << std::endl; }
};
class B : public A {
public:
B() {}
void print() { std::cout << "B" << std::endl; }
};
class C : public A {
public:
C() {}
void print() { std::cout << "C" << std::endl; }
};
int main() {
A a;
B b;
C c;
A* ptr_b = &b;
A* ptr_c = &c;
ptr_b->print();
ptr_c->print();
return 0;
}
运行上述代码,得到的结果都是输出A的,这是因为在定义ptr_b
和ptr_c
时虽然指向的是B对象和C对象的地址,但是因为编译器在编译时已经确定了使用基类的print()函数,所以只会输出A。这时我们可以使用动态多态的方法来解决此类问题。
#include <iostream>
class A {
public:
A() {}
virtual void print() { std::cout << "A" << std::endl; }
};
class B : public A {
public:
B() {}
void print() { std::cout << "B" << std::endl; }
};
class C : public A {
public:
C() {}
void print() { std::cout << "C" << std::endl; }
};
int main() {
A a;
B b;
C c;
A* ptr_b = &b;
A* ptr_c = &c;
ptr_b->print();
ptr_c->print();
return 0;
}
这时ptr_b
和ptr_c
指向的就是B的对象和C的对象了。查看类的大小会发现比原来的大了,这是因为有虚函数的类在实例化后会有虚函数表(vtable),而这个表是对每个该类的对象共享,也就是说该类的所有对象共用一个虚函数表。而这些对象通过虚表指针来判断自己的虚函数表。例如:
class A {
public:
A() {}
virtual void print1() { std::cout << "A->v1" << std::endl; }
virtual void print2() { std::cout << "A->v2" << std::endl; }
};
class B : public A {
public:
B() {}
virtual void print1() { std::cout << "B->v1" << std::endl; }
void fun() { std::cout << "B->B" << std::endl; }
};
class C : public B {
public:
C() {}
virtual void print2() { std::cout << "C->v2" << std::endl; }
void fun() { std::cout << "C" << std::endl; }
};
可以看出A类有两个虚函数,那么实例化A类的话对象通过虚表指针会指向A类的虚函数。
实例化B类的话,B类对象的print1指向自己的虚函数表,print2指向A类的虚函数表。
实例化C类,C类对象的print2指向自己的虚函数表,print1指向B类的虚函数表。