C++中调用虚方法触发访问违规问题求助
刚好做过类似的3D场景渲染架构,给你梳理一下实现思路和具体代码吧:
实现方案与代码示例
1. 先定义各个基础类
首先是Transformable普通类,咱们给它加些常用的变换方法:
class Transformable { public: void translate(float x, float y, float z) { // 这里写平移的具体逻辑,比如更新内部的变换矩阵 } void rotate(float angle, float x, float y, float z) { // 旋转逻辑实现 } // 缩放等其他变换方法可以按需添加 };
然后是核心的纯虚接口Renderable,它只负责定义绘制规范:
class Renderable { public: virtual ~Renderable() = default; // 必须加虚析构,不然子类析构会出问题 virtual void draw() const = 0; // 纯虚方法,强制子类实现绘制逻辑 };
接下来是GeomObject,它要同时继承Renderable(拿到绘制接口)、Transformable(拿到变换能力),还要继承普通类SceneObject(作为场景对象的通用基类):
// 先定义SceneObject通用基类 class SceneObject { protected: bool isRenderable = true; // 所有对象默认可渲染 public: virtual ~SceneObject() = default; // 同样加虚析构,支持多态 bool getIsRenderable() const { return isRenderable; } void setIsRenderable(bool val) { isRenderable = val; } // 还可以加些通用属性,比如对象名称、ID之类的 }; // 定义GeomObject class GeomObject : public SceneObject, public Renderable, public Transformable { public: void draw() const override { if (!getIsRenderable()) return; // 先检查是否允许渲染 // 这里写具体的绘制逻辑,比如绑定顶点缓冲区、应用材质、调用API绘制 std::cout << "Rendering geometric object..." << std::endl; } // 可以加几何对象专属的方法,比如设置顶点数据、材质等 };
2. 实现Scene类的遍历与渲染逻辑
Scene类要负责管理所有场景对象,遍历的时候判断哪些是可渲染的,然后调用draw方法:
#include <vector> #include <memory> #include <iostream> class Scene { private: std::vector<std::unique_ptr<SceneObject>> sceneObjects; // 用智能指针管理对象,避免内存泄漏 public: // 添加对象到场景 void addObject(std::unique_ptr<SceneObject> obj) { sceneObjects.push_back(std::move(obj)); } // 遍历所有对象,渲染可渲染的对象 void renderScene() { for (const auto& obj : sceneObjects) { // 第一步:先检查对象的isRenderable标记 if (!obj->getIsRenderable()) { continue; } // 第二步:判断对象是否实现了Renderable接口 const Renderable* renderableObj = dynamic_cast<const Renderable*>(obj.get()); if (renderableObj != nullptr) { renderableObj->draw(); // 调用多态的draw方法 } } } };
3. 实际使用示例
int main() { Scene myScene; // 创建一个立方体对象,设置平移后加入场景 auto cube = std::make_unique<GeomObject>(); cube->translate(2.0f, 0.0f, 0.0f); myScene.addObject(std::move(cube)); // 创建一个球体对象,标记为不可渲染后加入场景 auto sphere = std::make_unique<GeomObject>(); sphere->setIsRenderable(false); myScene.addObject(std::move(sphere)); // 渲染整个场景 myScene.renderScene(); // 只会输出立方体的渲染信息,球体被跳过 return 0; }
几个关键注意点
- 虚析构函数:所有作为基类的类(Renderable、SceneObject)必须加虚析构,不然通过基类指针销毁子类对象时,子类的析构函数不会被调用,会导致内存泄漏。
- dynamic_cast的使用:用来安全地判断对象是否实现了Renderable接口,只有转换成功(指针不为空)才调用draw方法,这是C++中处理多态类型检查的标准方式。
- isRenderable标记:这个额外的标记可以让你临时禁用某个对象的渲染,不需要修改对象的类型,比单纯依赖类型转换更灵活。
- 智能指针:用
std::unique_ptr管理场景对象,不用手动释放内存,避免内存泄漏问题。
内容的提问来源于stack exchange,提问作者3dmodels
相关产品推荐
相关产品推荐

