You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过基类的虚调用访问派生类的protected clone函数?

关于《Accelerated C++》13章句柄类中protected虚clone的调用问题

嘿,这个问题刚好是书中句柄类实现的核心细节,我来给你一步步讲清楚怎么解决~

首先得明确咱们的目标:Student_Info作为句柄类,要实现深拷贝,避免多个句柄共享同一个底层对象的问题。而clone虚函数就是用来让底层对象(不管是Core还是Grade)自己创建一个完全一样的副本,这也是虚函数多态性的典型应用。

为什么protected的clone能被虚调用?

首先要记住C++里的protected访问规则:基类的protected成员可以被基类自身、基类的友元,以及所有派生类的成员函数访问。而我们的关键操作是在Student_Info里调用clone,所以第一步要让Student_Info成为Core(以及Grade)的友元,这样它就能合法访问protected的clone函数了。

具体实现步骤

1. 定义基类Core的clone函数

在Core里声明一个protected的虚clone,让它返回一个新的Core对象副本:

class Core {
    // 让句柄类能访问protected的clone
    friend class Student_Info;
    // 其他成员(比如name、midterm等)...
protected:
    // 虚函数,返回当前对象的副本
    virtual Core* clone() const {
        return new Core(*this);
    }
    // 其他protected成员...
};

2. 在派生类Grade中重写clone

Grade作为Core的派生类,同样声明protected的clone,但返回Grade类型的副本(这里可以用协变返回类型,也就是返回Grade*而非Core*,C++允许虚函数返回派生类指针,只要它是基类返回类型的子类):

class Grade : public Core {
    // 同样让句柄类访问
    friend class Student_Info;
    // 额外成员(比如final_exam等)...
protected:
    // 重写基类的clone,返回Grade对象副本
    Grade* clone() const override {
        return new Grade(*this);
    }
    // 其他protected成员...
};

3. 在Student_Info的拷贝构造中调用clone

Student_Info内部持有一个Core*指针(指向Core或Grade对象),在拷贝构造时,我们通过这个指针调用clone——因为clone是虚函数,会根据指针实际指向的对象类型,动态调用对应的clone函数:

class Student_Info {
public:
    // 默认构造函数
    Student_Info() : p(nullptr) {}
    // 拷贝构造函数:调用clone创建深拷贝
    Student_Info(const Student_Info& other) 
        : p(other.p ? other.p->clone() : nullptr) {}
    
    // 别忘了赋值运算符也要做类似处理(RAII风格)
    Student_Info& operator=(const Student_Info& other) {
        if (this != &other) {
            // 先释放当前对象
            delete p;
            // 调用clone创建新副本
            p = other.p ? other.p->clone() : nullptr;
        }
        return *this;
    }

    // 析构函数释放底层对象
    ~Student_Info() { delete p; }

private:
    Core* p; // 指向Core或Grade的底层对象
};

关键原理拆解

  • 友元声明:让Student_Info能突破protected权限,合法调用clone函数。
  • 虚函数动态绑定:当调用other.p->clone()时,不管p的静态类型是Core*,只要它实际指向的是Grade对象,就会调用Grade::clone,返回一个Grade的副本,完美实现了“什么类型的对象就拷贝什么类型”的需求。
  • protected的意义:把clone设为protected,是为了封装——只有负责管理对象生命周期的句柄类(Student_Info)和派生类自己能调用它,外部代码不能随意创建对象副本,保证了类的封装性。

内容的提问来源于stack exchange,提问作者Chris Jing

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 03:26:00