尝试创建子类的实例时崩溃

问题描述 投票:0回答:1

我有

_Object
这是一个父类,我有
_Button
这是一个子类。这是我可怕的代码:

class _Object {
protected:
    SDL_Texture* texture;
    const char* image_path;
    static uint64_t count; /* 18,446,744,073,709,551,615 objects ought to be enough for anybody */
    uint_least32_t group;
    static std::set<int_fast64_t> z_order_set;
    int_fast64_t z_order;
    int64_t x;
    int64_t y;
    uint8_t alpha;
    uint16_t rot;
    float scale;
    static int_fast64_t uniquify_z_order(int_fast64_t& z_order) {
        if (z_order >= 0) {
            while (z_order_set.find(z_order) != z_order_set.end()) {
                z_order++;
                if (z_order == INT_FAST64_MAX) {
                    goto EXCEPTION;
                }
            }
        } else {
            while (z_order_set.find(z_order) != z_order_set.end()) {
                z_order--;
                if (z_order == INT_FAST64_MIN) {
                    goto EXCEPTION;
                }
            }
        }
        return z_order;
EXCEPTION:
        z_order = 0;
        return 0;
    }
public:
    _Object() = delete;
    _Object(SDL_Renderer* rend, int_fast64_t z_order, const char* image, int x, int y) {
        _constructor(rend, z_order, image, x, y, ((uint8_t)255), ((uint16_t)0), 100.0f);
    }
    _Object(SDL_Renderer* rend, int_fast64_t z_order, const char* image, int x, int y, uint8_t alpha, uint16_t rot, float scale) {
        _constructor(rend, z_order, image, x, y, alpha, rot, scale);
    }
    _Object(SDL_Renderer* rend, _Object* obj) {
        _constructor(rend, obj->z_order, obj->image_path, obj->x, obj->y, obj->alpha, obj->rot, obj->scale);
    }
    ~_Object() {
        SDL_DestroyTexture(this->texture);
    }
    /* Constructor */
    void _constructor(SDL_Renderer* rend, int_fast64_t z_order, const char* image_path, int x, int y, uint8_t alpha, uint16_t rot, float scale) {
        if (z_order != 0) {
            if (z_order_set.find(z_order) != z_order_set.end()) {
                stacktrace(module::warning, "z_order (%lld) is already in use. New unique z_order: %lld", z_order, uniquify_z_order(z_order));
                if (z_order == 0) {
                    stacktrace(module::error, "No free z_order left. Object discarded.");
                    this->z_order_set.erase(z_order);
                    throw OUT_OF_Z_ORDER;
                }
            }
            this->z_order_set.insert(z_order);
            this->z_order = z_order;
        } else {
            stacktrace(module::error, "Attempted to use zero as a z_order (reserved for player). Object discarded.");
            throw OUT_OF_Z_ORDER;
        }
        this->texture = IMG_LoadTexture(rend, image_path);
        if (!this->texture) {
            stacktrace(module::error, "Couldn't load \"%s\". Object discarded.", image_path);
            this->z_order_set.erase(z_order);
            throw;
        }
        this->x = x;
        this->y = y;
        this->alpha = alpha;
        this->rot = rot;
        this->scale = scale;
    }
    /* Methods */
    SDL_Texture* get_texture(void) const {
        return this->texture;
    }
    std::pair<int64_t, int64_t> get_position(void) const {
        return {this->x, this->y};
    }
    void move_to(int64_t x, int64_t y) {
        this->x = x;
        this->y = y;
    }
    void move_from(int x, int y) {
        this->x += x;
        this->y += y;
    }
};

uint64_t _Object::count = 0;
std::set<int_fast64_t> _Object::z_order_set;

class _Button : public _Object {
    const char* image = path::img::menu_button; //the path is valid, i double-checked
public:
    _Button() = delete;
    _Button(SDL_Renderer* rend, int_fast64_t z_order, int x, int y)
        : _Object(rend, z_order, image, x, y) {}
    _Button(SDL_Renderer* rend, int_fast64_t z_order, int x, int y, uint8_t alpha, uint16_t rot, float scale)
        : _Object(rend, z_order, image, x, y, alpha, rot, scale) {}
    ~_Button() = default;
    bool was_clicked(int mouse_x, int mouse_y) {
        int txtrw, txtrh;
        SDL_QueryTexture(this->get_texture(), NULL, NULL, &txtrw, &txtrh);
        auto [xpos, ypos] = this->get_position();
        return (mouse_x >= xpos && mouse_x <= xpos + txtrw && mouse_y >= ypos && mouse_y <= ypos + txtrh);
    }
};

问题是,如果我尝试创建

_Object
的实例,它工作得很好:

_Object* my_object = new _Object(rend, 69, "whatever.png", 0, 0); //fine

但是当我尝试创建

_Button
的实例时,程序崩溃了:

_Button* my_button = new _Button(rend, 420, 0, 0); //crash

我还注意到复制构造函数也不起作用:

_Object* my_object = new _Object(rend, 69, "whatever.png", 0, 0); //fine
_Object* my_object_2 = new _Object(rend, my_object); //crash

我想了解可能导致这些问题的原因,因为我不知道。也许我做错了什么。

我尝试向chatgpt 寻求解决方案。浪费了时间。

c++ oop inheritance crash
1个回答
0
投票

这是关于初始化的顺序。首先初始化基类,然后才初始化派生类的路径变量。这给了基类一个未初始化的指针。

标准说:

在非委托构造函数中,初始化在 以下顺序:

— 首先,且仅适用于 大多数派生类(6.7.2),虚拟基类在中初始化 它们在深度优先从左到右遍历时出现的顺序 基类的有向无环图,其中“从左到右”是 基类在派生类中的出现顺序 基本说明符列表。

— 那么,直接基类是 按照声明顺序初始化,因为它们出现在 基本说明符列表(无论内存初始化器的顺序如何)。

— 然后,非静态数据成员按顺序初始化 它们是在类定义中声明的(同样,无论 内存初始化器的顺序)。

—最后, 执行构造函数主体的复合语句。

[注6: 声明令的目的是确保基地和成员 子对象以与初始化相反的顺序销毁。 -结尾 注]

© www.soinside.com 2019 - 2024. All rights reserved.