C++继承中如何正确调用基类函数?代码详解
新手必问:为啥我写的子类吃掉了父类功能?
你是不是遇到过这种情况?子类明明继承了父类,结果一运行程序,父类的方法就像凭空消失了一样。别慌!这八成是因为你在子类里??手滑重写(override)了父类方法??,就像给自家窗户贴了磨砂膜——外面的风景还在,但就是看不到了。
咱们举个栗子:
cpp复制class 老式手机 { public: void 打电话() { cout << "嘟嘟嘟...正在拨号" << endl; } }; class 智能机 : public 老式手机 { public: void 打电话() { cout << "正在搜索5G信号..." << endl; } }; 智能机 我的手机; 我的手机.打电话(); // 只会输出"正在搜索5G信号..."
这时候你就会发现,父类的打电话功能完全被覆盖了。别急,接下来教你三招保命技巧。
第一招:魔法双冒号(::)
记住这个口诀:??"双冒号破屏障,直捣黄龙找爹娘"??。在子类方法里用父类名::方法名()
,就像给代码装了个GPS导航。
看这个电动车继承汽车的案例:
cpp复制class 汽车 { public: void 启动() { cout << "引擎点火成功!" << endl; } }; class 电动车 : public 汽车 { public: void 启动() { **汽车::启动();** // 关键操作在这里 cout << "动力电池已激活" << endl; } };
这时候执行电动车 小鹏P7; 小鹏P7.启动();
就会先输出父类的引擎点火,再显示电池激活。是不是比单纯覆盖更智能?
第二招:构造函数的特殊通道
创建子类对象时,??父类构造函数会自动先执行??,这个特性就像坐电梯——必须先到一楼才能上十楼。但如果你想定制化初始化流程,就得这么写:
cpp复制class 数据库连接 { public: 数据库连接(string 地址) { cout << "正在连接" << 地址 << endl; } }; class MySQL连接 : public 数据库连接 { public: **MySQL连接(string 地址) : 数据库连接(地址)** { // 重点在这行 cout << "载入MySQL驱动" << endl; } };
当创建MySQL连接 我的数据库("127.0.0.1");
时,控制台会先显示父类的连接信息,再输出子类的驱动加载提示。这个冒号语法就像VIP通道,保证父类构造优先执行。
第三招:虚函数回溯大法
当遇到多态场景时,??给父类方法加virtual关键字??,相当于给方法装了个弹簧床。子类跳上去之后,还能随时弹回父类版本:
cpp复制class 支付接口 { public: virtual void 付款() { cout << "基础支付通道已打开" << endl; } }; class 微信支付 : public 支付接口 { public: void 付款() override { cout << "扫描二维码..." << endl; **支付接口::付款();** // 关键回溯 } };
这时候如果用支付接口* 支付方式 = new 微信支付; 支付方式->付款();
,就会先执行子类的扫码操作,再调用父类的支付通道开启。注意这个override关键字就像安全绳,能防止手滑写错方法签名。
三大坑爹陷阱提醒
- ??起名鬼才的报应??:如果父类方法叫
open()
,子类非要改成Open()
,编译器会认为这是两个毫不相干的方法。记住C++??区分大小写??! - ??权限不足的尴尬??:要是父类方法设成private权限,就像在自家装了防盗门——子类根本摸不到把手,更别说调用了
- ??二重唱的混乱??:多重继承时如果两个父类都有同名方法,必须明确指定
父类A::方法()
或父类B::方法()
,否则编译器会当场懵圈
个人观点:其实调用基类函数就像组装乐高,关键要找准拼接点。很多新人容易在重写方法后忘记保留原有功能,这时候用双冒号语法最稳妥。不过要注意,如果是做框架开发,建议多用虚函数实现多态,这样后续扩展性更好。记住,代码不是越炫技越好,??能让人一眼看懂的设计才是好设计??。
本文由嘻道妙招独家原创,未经允许,严禁转载