第18课 - 多态与继承 - 下
Source Example 1: #include <iostream> /* run this program using the console pauser or add your own getch, system("pause") or input loop */ class Parent { public: virtual void func() { printf("Parent->"); printf("func()!\n"); } virtual void func(int i) { printf("Parent->"); printf("func(int i)!\n"); } virtual void func(int i, int j) { printf("Parent->"); printf("func(int i, int j)!\n"); } }; class Child : public Parent { public: virtual void func(int i) { printf("Child->"); printf("func(int i)!\n"); } virtual void func(int i, int j) { printf("Child->"); printf("func(int i, int j)!\n"); } void func(int i, int j, int k) { printf("Child->"); printf("func(int i, int j, int k)!\n"); } }; void run(Parent* p) { p->func(1,2); } int main(int argc, char** argv) { Parent p; Child c; p.func(); p.func(1); p.func(1,2); /* 编译报错,因为void func(int i, int j, int k)函数将继承的func函数名称覆盖了 */ /* 并没有发生函数重载,函数重载发生在同一作用域之间 */ //c.func(); /* 这样才能调用父类中的func函数 */ c.Parent::func(); /* Child里面定义的两个func函数处于同一作用域,可以发生重载 */ c.func(1,2); printf("\n"); /* 会发生多态 */ run(&p); run(&c); return 0; }
1.1 重载与重写区别
通过虚函数表指针VPTR调用重写函数是在程序运行时进行的,因此需要寻址操作才能真正的确定应该调用的函数。
结论:构造函数中调用虚函数无法实现多态。
Source Example2.2(构造函数中的"多态") #include <iostream> /* run this program using the console pauser or add your own getch, system("pause") or input loop */ class Parent { public: Parent() { this->func(); } virtual void func() { printf("Parent->"); printf("func()!\n"); } }; class Child : public Parent { public: virtual void func(int i) { printf("Child->"); printf("func(int i)!\n"); } }; int main(int argc, char** argv) { /* 会调用父类的func函数 */ Parent p; /* * 1. 首先会执行父类函数的构造函数,此时VPTR指针指向父类的虚函数表 * 2. 调用虚函数表的func函数,即父类中的func函数 * 3. 其次会执行子类函数的构造函数,此时VPTR指针指向子类的虚函数表 * 4. 因此会调用父类的func函数,多态并没有发生 * 5. 结论,构造函数中无法实现多态 */ Child c; return 0; } 
在进行面向对象分析时,会有一些抽象的概念
在现实中需要知道图像的具体类型才能球面积,所以对概念上的"图形"求面积是没有意义的!
3.2 用Shape作为基类进行继承
Source Example 3.2: #include <iostream> /* run this program using the console pauser or add your own getch, system("pause") or input loop */ class Shape{ public: virtual double area() { return 0; } }; class Rectangle : public Shape{ protected: int a; int b; public: Rectangle(int a, int b) { this->a = a; this->b = b; } virtual double area() { return a * b; } }; class Circle : public Shape{ protected: int r; public: Circle(int r) { this->r = r; } virtual double area() { return 3.14 * r * r; } }; void area(Shape* s) { printf("area = %lf\n", s->area()); } int main(int argc, char** argv) { Rectangle r(1,2); Circle c(3); Shape s; area(&r); area(&c); area(&s); return 0; }
Source Example3.4: #include <iostream> /* run this program using the console pauser or add your own getch, system("pause") or input loop */ class Shape{ public: virtual double area() = 0; }; class Rectangle : public Shape{ protected: int a; int b; public: Rectangle(int a, int b) { this->a = a; this->b = b; } /* 子类中必须要有重写Shape类中的area函数,不然会报错 */ virtual double area() { return a * b; } }; class Circle : public Shape{ protected: int r; public: Circle(int r) { this->r = r; } /* 子类中必须要有重写Shape类中的area函数,不然会报错 */ virtual double area() { return 3.14 * r * r; } }; void area(Shape* s) { printf("area = %lf\n", s->area()); } int main(int argc, char** argv) { Rectangle r(1,2); Circle c(3); /* 编译会报错,因为不能定义抽象类的对象 */ Shape s; area(&r); area(&c); return 0; } 文章来源: 第18课 - 多态与继承 - 下