函数覆盖:
发生在使用父类指针或引用指向子类对象时:
1. 子类对象退化为父类对象
2. 只能访问父类中定义的成员。
3. 可以直接访问被子类覆盖的同名成员。
#include <iostream> #include <string> using namespace std; class Parent { public: void func(int x) {} void func(int x, int y) {} }; class Child : public Parent { public: void func(int x, int y, int z) {} }; int main() { Parent p; Child c; p = c; // 用子类赋值给父类 Parent p1(c); // 用子类初始化父类 Parent& cite_p = c; // 父类引用子类 编译器只能根据指针所指向的类型来判断所指向的对象的类型-->也就是Parent Parent* point_p = &c; // 父类指向子类 指针所指向的类型(parent)来判断所指向的对象的类型(parent) cite_p.add(1); // 子类退化为父类 cite_p.add(1,1); // 子类退化为父类 cite_P.add(1,1,1) // error 子类退化为父类,无法引用子类函数 point_p.add(1); // 子类退化为父类 point_p.add(1,1); // 子类退化为父类 point_p.add(1,1,1) // error 子类退化为父类,无法通过指针访问子类函数 return 0; }
函数重写:
1. 子类中重定义了与父类完全相同的函数。
2. 重定义发生在继承中时就叫重写。
3. 函数重写只是一种特殊的同名覆盖(函数名和参数完全相同的覆盖)。
4. 依旧可以通过作用域分辨符来访问被重写的函数。
#include <iostream> #include <string> using namespace std; class Parent { public: void print() { cout << "I'm Parent." << endl; } }; class Child : public Parent { public: void print() // 函数重写 { cout << "I'm Child." << endl; } }; void how_to_print(Parent* p) { p->print(); } int main() { Parent p; Child c; how_to_print(&p); // I'm Parent. 退化为父类指针,之可以访问父类的成员函数和成员变量。 how_to_print(&c); // I'm Parent. 退化为父类的指针。函数重写却没有用,原因是指针所指向的类型(parent)来判断所指向的对象的类型(parent) c.Parent::print(); // I'm Parent. 通过作用域访问符来访问被重写的函数 c.print(); // I'm Child. 函数覆盖
return 0; }
Java覆盖是:方法名相同,参数列表相同,返回值相同。
C++覆盖是:方法名相同, 返回值相同。
在Java中出现子类的方法的方法名与父类相同时,会继承父类的同名函数,子类可以访问。
在C++中出现子类的函数的函数名与父类相同时,会覆盖父类的同名函数,子类无法访问。
#include<iostream> using namespace std; class Parent { public: int add(int val1) { return (val1); } }; class Child : public Parent { public: int add(int val1, int val2) { return (val1 + val2); } int add(int val1, int val2, int val3) { return (val1 + val2 + val3); } }; int main(void) { Child c1; Child* c2 = new Child(); cout << c1.add(1) << endl; //error 函数同名但参数列表不同会隐藏父类同名函数 return 0; }
class Parent { public int add(int val1) { return (val1); } } class Child extends Parent { public int add(int val1, int val2) { return (val1 + val2); } public int add(int val1, int val2, int val3) { return (val1 + val2 + val3); } } public class Chapter8_1 { public static void main(String[] args) { Child c = new Child(); System.out.println(c.add(1)); //ok 同名函数但参数列表不同并不会隐藏 } }
由于编译器对指针的处理方式,所以当对重写后的函数进行指针访问时会出错。
父子间的兼容性:
1. 子类对象可以直接赋值给父类对象:Parent p; Child c; p = c;
2. 子类对象可以直接初始化父类对象:Parent p(c);
2. 父类对象可以直接引用子类对象:Parent& p = c;
3. 父类对象可以直接指向子类对象:Parent* p = &c;
以上是编译器将子类对象退化为父类对象,从而可以初始化父类。所以以上父类对象(指针,引用)只能访问父类的成员。
问题: 子类可以重写父类的成员,根据兼容性使用父类指针后又无法访问重写的函数。
可以通过强制转化将父类对象转化为子类对象。
Child* c = (static_cast*)<Child*>p;