1. 主页 > 大智慧

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关键字就像安全绳,能防止手滑写错方法签名。


三大坑爹陷阱提醒

  1. ??起名鬼才的报应??:如果父类方法叫open(),子类非要改成Open(),编译器会认为这是两个毫不相干的方法。记住C++??区分大小写??!
  2. ??权限不足的尴尬??:要是父类方法设成private权限,就像在自家装了防盗门——子类根本摸不到把手,更别说调用了
  3. ??二重唱的混乱??:多重继承时如果两个父类都有同名方法,必须明确指定父类A::方法()父类B::方法(),否则编译器会当场懵圈

个人观点:其实调用基类函数就像组装乐高,关键要找准拼接点。很多新人容易在重写方法后忘记保留原有功能,这时候用双冒号语法最稳妥。不过要注意,如果是做框架开发,建议多用虚函数实现多态,这样后续扩展性更好。记住,代码不是越炫技越好,??能让人一眼看懂的设计才是好设计??。

本文由嘻道妙招独家原创,未经允许,严禁转载