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

实现Visitor设计模式时遭遇编译错误,寻求技术帮助

解决Visitor模式实现中的编译错误与逻辑问题

我来帮你逐一排查并解决这些问题:

问题1:前向声明导致的未定义类型错误

你的代码中,Forma类的accept函数在Operatie类完全定义之前就尝试调用op->vizitare(this),但此时编译器只知道Operatie是一个类的前向声明,不知道它的成员函数vizitare的具体结构,因此无法解析这个调用。

修正方法:
将Forma类的accept设为纯虚函数(符合抽象基类的设计,强制子类必须实现该方法),同时调整类的声明顺序,确保Operatie类在子类实现accept之前完成定义:

class Forma {
public:
    // 纯虚函数,子类必须实现
    virtual void accept(Operatie * op) = 0;
    Forma(void){};
    virtual ~Forma(void){}; // 添加虚析构,确保子类析构被正确调用
};

问题2:悬挂指针引发的内存安全问题

Editor::insert函数接收Forma对象的值,然后把局部对象的地址存入链表。当insert函数执行完毕后,这个局部对象会被销毁,链表中的指针就变成了悬挂指针,后续访问会导致未定义行为(比如程序崩溃、输出乱码)。

修正方法:
修改insert函数接收Forma*类型的参数,让调用者传入动态分配的对象指针,同时在Editor的析构函数中释放这些对象避免内存泄漏:

// Editor类的insert方法修改
void insert(Forma* obj){forme.insert(forme.end(), obj);};

// Editor的析构函数添加内存释放逻辑
~Editor(void){
    for(auto it = forme.begin(); it != forme.end(); ++it){
        delete *it;
    }
};

问题3:缺少必要头文件与命名空间问题

main函数中使用了cout和endl,但没有包含<iostream>头文件,而且这些属于std命名空间,必须显式指定才能使用。

修正方法:
添加头文件并使用标准命名空间:

#include <iostream>

// 在main中使用std::前缀,或者全局声明(不推荐全局,但可简化代码)
std::cout << editor.calculeazaArieTotala() << std::endl;

问题4:计算逻辑与拼写错误

你写的面积、周长公式完全错误,还有变量名拼写失误:

  • 圆的面积应为 M_PI * r * r(你写成了M_PI * r)
  • 矩形的面积应为 长 × 宽(你写成了长 + 宽)
  • 圆的周长应为 2 * M_PI * r(你写成了面积公式M_PI * r * r)
  • Perimetru类的实例名拼写错误:permietru → perimetru

修正方法:
修改Arie和Perimetru类的计算逻辑:

// Arie类的vizitare方法修正
void vizitare(Cerc* obj) override {arie += M_PI * obj->getRaza() * obj->getRaza();};
void vizitare(Dreptunghi* obj) override {arie += obj->getLungime() * obj->getLatime();};

// Perimetru类的vizitare方法修正
void vizitare(Cerc* obj) override {perimetru += 2 * M_PI * obj->getRaza();};
void vizitare(Dreptunghi* obj) override {perimetru += 2*(obj->getLungime() + obj->getLatime());};

// main中的变量名修正
Perimetru perimetru;

完整修正后的代码

#define _USE_MATH_DEFINES
#include <list>
#include <iostream>
#include "math.h"

// 前向声明
class Operatie;
class Cerc;
class Dreptunghi;

class Forma {
public:
    virtual void accept(Operatie * op) = 0;
    Forma(void){};
    virtual ~Forma(void){};
};

class Operatie{
public:
    virtual void vizitare(Cerc* obj) = 0;
    virtual void vizitare(Dreptunghi* obj) = 0;
    Operatie(void){};
    virtual ~Operatie(void){};
};

class Cerc : public Forma {
protected:
    int raza;
public:
    void accept(Operatie * op) override {op->vizitare(this);};
    int getRaza(){return raza;};
    Cerc(void):raza(3){};
    ~Cerc(void){};
};

class Dreptunghi : public Forma {
protected:
    int lungime;
    int latime;
public:
    void accept(Operatie * op) override {op->vizitare(this);};
    int getLungime(void){return lungime;};
    int getLatime(void){return latime;};
    Dreptunghi(void):lungime(3),latime(3){};
    ~Dreptunghi(void){};
};

class Arie : public Operatie {
private:
    double arie;
public:
    double getResult(){return arie;};
    void vizitare(Cerc* obj) override {arie += M_PI * obj->getRaza() * obj->getRaza();};
    void vizitare(Dreptunghi* obj) override {arie += obj->getLungime() * obj->getLatime();};
    Arie(void): arie(0) {};
    ~Arie(void){};
};

class Perimetru : public Operatie {
private:
    double perimetru;
public:
    double getResult(){return perimetru;};
    void vizitare(Cerc* obj) override {perimetru += 2 * M_PI * obj->getRaza();};
    void vizitare(Dreptunghi* obj) override {perimetru += 2*(obj->getLungime() + obj->getLatime());};
    Perimetru(void):perimetru(0){};
    ~Perimetru(void){};
};

class Editor{
private:
    std::list<Forma*> forme;
public:
    Editor(void){};
    void insert(Forma* obj){forme.insert(forme.end(), obj);};
    double calculeazaArieTotala(){
        Arie arie;
        for(std::list<Forma *>::iterator it = forme.begin(); it != forme.end(); ++it){
            (*it)->accept(&arie);
        }
        return arie.getResult();
    };
    double calculeazaPerimetrulTotal(){
        Perimetru perimetru;
        for(std::list<Forma *>::iterator it = forme.begin(); it != forme.end(); ++it){
            (*it)->accept(&perimetru);
        }
        return perimetru.getResult();
    };
    ~Editor(void){
        for(auto it = forme.begin(); it != forme.end(); ++it){
            delete *it;
        }
    };
};

int main(void){
    Editor editor;
    editor.insert(new Cerc());
    editor.insert(new Dreptunghi());
    
    std::cout << "Arie totala: " << editor.calculeazaArieTotala() << std::endl;
    std::cout << "Perimetru total: " << editor.calculeazaPerimetrulTotal() << std::endl;
    
    return 0;
}

额外优化说明

  • 给基类添加了虚析构函数,确保通过基类指针删除子类对象时,子类的析构函数能被正确调用。
  • 使用override关键字显式标记重写的虚函数,提升代码可读性,同时让编译器帮你检查是否正确重写了基类方法。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 04:40:31