前言:还是以实战为导向,遇到问题查找问题,最近需要NDK开发,所以就得继续重温学习c++,现把c++继承中子类和父类函数同名问题记录下
一、继承简介
面向对象程序设计的核心思想是数据抽象,继承和动态绑定(封装,继承,多态)。通过数据抽象可以将类的接口和实现分离;通过继承可以定义相似的类型;通过动态绑定可以在一定程度上忽略相似类型的区别,而以统一的方式使用它们的对象。继承有基类和派生类(父类和子类)。
如果不是很好理解可以网搜下相关内容。
二、继承中同名问题
一般情况下,我们写一个父类,然后写一个子类,子类根据继承关系继承了父类的成员函数,并可使用父类这些成员函数,然后,再根据子类的具体功能去添加些成员变量。继承最开始讲都是这样的内容,这当然不能满足我们需求,因为有时候我们感觉父类中的有些函数功能还不错,但是不同的子类 的需求不同,有些想直接使用父类的函数,有些想在父类的这个函数上面做些修改,因此就出现了子类和父类同名的函数。
三、代码说明
#define _CRT_SECURE_NO_WARNINGS #include#include #include using namespace std; class A { public: void print() { cout<<"类A中的print()函数" << endl; } virtual void virtualPrint() { cout << "类A中的virtualPrint()函数" << endl; } private: }; class B:public A { public: //派生类的同名函数会屏蔽基类的同名成员函数 //函数原型一样,娇函数重定义 void print() { cout << "类B中的print()函数" << endl; } //这里式重写了A类的virtualPrint方法 void virtualPrint() { cout << "类B中的virtualPrint()函数" << endl; } private: }; int main() { //若子类想要调用父类的函数,则需要使用子类实例.父类::函数名()形式 //覆盖---->多态(virtual) //父类指针被子类对象初始化 //通过实例调用 //即通过.进行调用时 //子类实例调用子类函数, //父类实例调用父类函数 cout << "************************" << endl; A a; a.print(); //父类实例调用父类函数 a.virtualPrint(); cout << "************************" << endl; B b; b.print(); //子类实例调用子类函数 b.virtualPrint(); cout << "************************" << endl; A* pAA = new A(); pAA->print(); pAA->virtualPrint(); cout << "************************" << endl; B* pB = new B(); pB->print(); pB->virtualPrint(); //通过"->"调用时 //当使用基类指针通过->调用时,根据指针的内容确定是 //基类地址还是子类地址,分别调用对应的函数,子类地址赋值给父类指针 //默认调用的是子类的函数, //但是可以通过父类指针->父类::函数名() 明确调用父类的函数. cout << "************************" << endl; A* pA = new B(); //此处基类指针指向的是派生类对象中的基类部分 //无法通过基类指针去调用派生类对象中的成员函数的 pA->print();//类A中的print()函数 //虚函数突破了这一点, //在派生类的基类部分中, //派生类的虚函数取代了基类原来的虚函数 //因此在使基类指针指向派生类对象后, //调用虚函数时就调用了派生类的虚函数。 //需要注意的是,只有用来virtual声明了虚函数后才具备以上功能 //如果不声明为虚函数,企图通过基类指针调用派生类的非虚函数是不行的 pA->virtualPrint(); }
3.1 实例调用成员函数
如果通过实例去调用,不用去管virtual,谁的实例就是调用谁的成员函数
3.2 指针类型调用成员函数
首先要明白,指针变量,代表的是一个地址
如上图pAA指针,指向的是父类A,那么自然是调用的父类A的成员函数,同理,pB也是一样
现在的问题也是不好理解的地方就在于:
当使用基类指针通过->调用时,这时候是调用的父类的还是子类的成员函数?
下面画个简单的继承关系图,(不是很严谨)。
这样应该就好理解了,pA是基类指针,指向的地址是B,然后B继承至A,所以pA真实指向的是B中A类部分,因此,对于没有virtual修饰的同名函数(即子类重写的同名函数),调用的还是父类的成员函数。
对于通过virtual修饰的同名函数(即子类重写的同名函数),已经被B进行重写了,调用的自然就是B中的重写函数了。



