You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

原型模式代码行为分析及疑似错误代码排查请求

原型模式C++代码错误检查与行为分析

首先先把你提供的不完整代码贴出来:

class Stooge { 
public: 
    virtual Stooge* clone() = 0; 
    virtual void slap_stick() = 0; 
}; 
class Curly : public Stooge { 
public: 
    Stooge* clone() { return new Curly; } 
    void slap_stick() { cout << "Curly: suffer abuse\n"; } 
}; 
Stooge* Factory::s_prototypes[] = { 0, new Larry, new Moe, new Curly }; 
Stooge* Factory::make_stooge( int choice = 3 ) { return s_prototypes[ch...

一、代码中存在的明显错误

我一眼就能看到好几个会导致编译失败或者逻辑问题的点:

  • 缺失必要头文件:代码里用了cout,但没有包含<iostream>头文件,编译器根本不知道cout是什么。
  • Factory类未定义:你直接使用了Factory::s_prototypesFactory::make_stooge,但完全没给出Factory类的定义,这是语法层面的硬伤。
  • Larry和Moe类缺失实现:静态数组里实例化了new Larrynew Moe,但这两个继承自Stooge的子类完全没定义,编译肯定会报“未定义类型”的错误。
  • 函数参数名错误make_stooge函数声明里的参数是choice,但函数体里写的是ch(从你没写完的代码能看出来是笔误),这会导致变量未定义的编译错误。
  • 命名空间问题cout属于std命名空间,要么写成std::cout,要么在代码开头加using namespace std;,不然编译器找不到这个符号。
  • 数组越界风险:默认参数choice = 3对应数组索引3(数组是{0, new Larry, new Moe, new Curly}),虽然这个索引是合法的,但如果传入大于3的数值,就会触发数组越界的未定义行为。

二、这段代码中原型模式的核心行为分析

虽然代码有问题,但能看出来它想实现的原型模式逻辑是清晰的:

  • 抽象原型类Stooge作为抽象基类,定义了两个核心方法:clone()(纯虚函数,要求子类实现克隆自身的逻辑)和slap_stick()(子类的业务方法)。
  • 具体原型类:比如Curly,它实现了clone()方法,返回一个新的Curly实例——这就是原型模式的核心:通过克隆已有对象来创建新对象,而不是直接调用构造函数。
  • 原型管理器(Factory类):Factory的静态数组s_prototypes用来存储各个具体Stooge子类的原型实例(Larry、Moe、Curly的实例),make_stooge方法根据传入的选择值,克隆对应索引的原型对象并返回。这种设计的好处是:
    1. 避免了直接依赖具体子类,实现了对象创建与使用的解耦;
    2. 如果需要新增Stooge子类,只需要添加新的原型到数组,修改Factory的逻辑即可,符合开闭原则;
    3. 克隆对象比直接创建对象更高效(尤其是对象初始化成本高的时候)。

修正后的示例代码

为了让这段代码能正常运行,我补全了缺失的部分:

#include <iostream>
using namespace std;

class Stooge { 
public: 
    virtual Stooge* clone() = 0; 
    virtual void slap_stick() = 0; 
    virtual ~Stooge() {} // 虚析构函数,避免内存泄漏
}; 

class Larry : public Stooge { 
public: 
    Stooge* clone() { return new Larry; } 
    void slap_stick() { cout << "Larry: slap forehead\n"; } 
};

class Moe : public Stooge { 
public: 
    Stooge* clone() { return new Moe; } 
    void slap_stick() { cout << "Moe: poke eyes\n"; } 
};

class Curly : public Stooge { 
public: 
    Stooge* clone() { return new Curly; } 
    void slap_stick() { cout << "Curly: suffer abuse\n"; } 
};

class Factory {
public:
    static Stooge* s_prototypes[];
    static Stooge* make_stooge(int choice = 3) {
        if (choice < 1 || choice > 3) return nullptr; // 边界检查
        return s_prototypes[choice]->clone();
    }
};

Stooge* Factory::s_prototypes[] = { nullptr, new Larry, new Moe, new Curly };

int main() {
    Stooge* stooge1 = Factory::make_stooge(1);
    Stooge* stooge2 = Factory::make_stooge(2);
    Stooge* stooge3 = Factory::make_stooge(); // 使用默认参数3

    stooge1->slap_stick();
    stooge2->slap_stick();
    stooge3->slap_stick();

    // 释放内存
    delete stooge1;
    delete stooge2;
    delete stooge3;
    // 注意:原型实例的内存这里没释放,实际项目中需要考虑管理方式
    return 0;
}

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

火山引擎 最新活动