c++ - 不完整类型的无效使用 "class"

标签 c++ qt forward-declaration

我知道有很多这样的问题,但不幸的是,经过数小时的谷歌搜索和浏览所有这些问题后,我读到的答案都没有帮助。因此,我正在制作我自己的问题版本。我收到的错误消息是:“错误:无效使用不完整类型‘std::iterator_traits::value_type {aka class Cell}’”我的代码:

细胞.h

#ifndef CELL_H
#define CELL_H

#include <QPushButton>
#include <QMouseEvent>
#include <vector>

class Padding;

class Cell : public QPushButton
{
    Q_OBJECT

    public:

        friend class Padding;
        Cell(int x, int y, Padding* padding, QWidget* parent = 0) : QPushButton(parent), x(x), y(y),
            padding(padding)
        {
            setFixedSize(20, 20);
        }
        Cell(const Cell& object) : QPushButton(), x(object.x), y(object.y), padding(object.padding)
        {
            setFixedSize(20, 20);
        }
        int getX() { return x; };
        int getY() { return y; };
        bool hasMine() { return mine; };
        void setHasMine(bool mine) { this -> mine = mine; };
        bool isFlagged() { return flagged; };
        bool didExplode() { return exploded; };
        bool getHasBeenClicked() { return hasBeenClicked; };
        void clicked();
        ~Cell() {};
        Cell operator=(const Cell& object)
        {
            if(&object == this)
            {
                return *this;
            }
            padding = object.padding;
            x = object.x;
            y = object.y;
            mine = object.mine;
            flagged = object.flagged;
            exploded = object.exploded;
            hasBeenClicked = object.hasBeenClicked;
            setFixedSize(20, 20);
            return *this;
        }

    private:

        Padding* padding;
        int x;
        int y;
        bool mine = false;
        bool flagged = false;
        bool exploded = false;
        bool hasBeenClicked = false;
        void mousePressEvent(QMouseEvent* e);
        void rightClicked();
};

#endif // CELL_H

细胞.cpp

#include "cell.h"
#include "padding.h"

void Cell::mousePressEvent(QMouseEvent* event)
{
    if(event -> button() == Qt::LeftButton)
    {
        clicked();
    }
    else if(event -> button() == Qt::RightButton)
    {
        rightClicked();
    }
}

void Cell::clicked()
{
    hasBeenClicked = true;
    // TODO: Set the button frame to flat. DONE.
    setFlat(true);
    // TODO: Make the button not click able. DONE.
    setEnabled(false);
    // TODO: Display appropriate number on the button, or mine and end the game. DONE.
    if(mine)
    {
        // TODO: Send game over signal and end the game.
        //setIcon(QIcon("mine_clicked.png"));
        setText("/");
        exploded = true;
        padding -> gameOver();
    }
    else
    {
        setText(QString::number(padding -> countMinesAround(this)));
    }
    if(padding -> countMinesAround(this) == 0)
    {
        // Trigger chain reaction; uncover many neighboring cells, if they are not mines.
        padding -> triggerChainReactionAround(this);
    }
}

void Cell::rightClicked()
{
    if(text() != "f")
    {
        setText("f");
        (padding -> minesLeft)--;
    }
    else
    {
        setText("");
        (padding -> minesLeft)++;
    }
    flagged = !flagged;
}

填充.h

#ifndef PADDING_H
#define PADDING_H

#include <QWidget>
#include <QGridLayout>
#include <vector>

class Cell;

class Padding : public QWidget
{
    Q_OBJECT

    public:

        friend class Cell;

        enum class Difficulty
        {
            Beginner,
            Intermediate,
            Advanced,
            Custom
        };

        Padding(QWidget* parent = 0);
        void newGame();
        void gameOver();
        void setLevel(Padding::Difficulty difficulty) { this -> difficulty = difficulty; };
        void setPaddingHeight(int height) { paddingHeight = height; };
        void setPaddingWidth(int width) { paddingWidth = width; };
        void setMines(int mines) { this -> mines = mines; };
        int getMinesLeft() { return minesLeft; };
        ~Padding() {};

    private:

        struct DifficultyLevelsProperties
        {
            struct BeginnerProperties
            {
                const int PADDING_HEIGHT = 9;
                const int PADDING_WIDTH = 9;
                const int MINES = 10;
            } Beginner;

            struct IntermediateProperties
            {
                const int PADDING_HEIGHT = 16;
                const int PADDING_WIDTH = 16;
                const int MINES = 40;
            } Intermediate;

            struct AdvancedProperties
            {
                const int PADDING_HEIGHT = 16;
                const int PADDING_WIDTH = 40;
                const int MINES = 99;
            } Advanced;
        } LevelProperties;

        Difficulty difficulty = Difficulty::Beginner;
        int paddingHeight;
        int paddingWidth;
        int mines;
        // Mines that are not flagged.
        int minesLeft;
        // Time in seconds since the game was started.
        int secondsSinceStart;
        std::vector<Cell> cells;
        QGridLayout* paddingLayout;
        const int CELLS_HEIGHT = 20;
        const int CELLS_WIDTH = 20;
        int countMinesAround(Cell*);
        void triggerChainReactionAround(Cell*);
        void updateSecondsSinceStart();
};

#endif // PADDING_H

填充.cpp

#include "padding.h"
#include <QGridLayout>
#include <QTimer>
#include <QTime>
#include <QDebug>
#include "cell.h"

Padding::Padding(QWidget* parent) : QWidget(parent)
{
    newGame();
    paddingLayout = new QGridLayout(this);
    paddingLayout -> setSpacing(0);
}

void Padding::newGame()
{
    if(difficulty == Padding::Difficulty::Beginner)
    {
        paddingHeight = LevelProperties.Beginner.PADDING_HEIGHT;
        paddingWidth = LevelProperties.Beginner.PADDING_WIDTH;
        mines = LevelProperties.Beginner.MINES;
    }
    else if(difficulty == Padding::Difficulty::Intermediate)
    {
        paddingHeight = LevelProperties.Intermediate.PADDING_HEIGHT;
        paddingWidth = LevelProperties.Intermediate.PADDING_WIDTH;
        mines = LevelProperties.Intermediate.MINES;
    }
    else if(difficulty == Padding::Difficulty::Advanced)
    {
        paddingHeight = LevelProperties.Advanced.PADDING_HEIGHT;
        paddingWidth = LevelProperties.Advanced.PADDING_WIDTH;
        mines = LevelProperties.Advanced.MINES;
    }
    minesLeft = mines;
    cells.clear();
    for(int i = 0; i < paddingHeight; i++)
    {
        for(int j = 0; j < paddingWidth; j++)
        {
            // TODO: Use smart pointers instead of raw pointers.
            Cell* cell = new Cell(j + 1, i + 1, this);
            cells.push_back(*cell);
            delete cell;
        }
    }
    qsrand(QTime::currentTime().msec());
    for(int i = 0; i < mines; i++)
    {
        // TODO: Fix the randomness of the numbers. DONE.
        cells[qrand() % (paddingHeight * paddingWidth) + 1].setHasMine(true);
    }
    for(int i = 0; i < cells.size(); i++)
    {
        paddingLayout -> addWidget(&cells[i], cells[i].getY(), cells[i].getX());
    }
}

void Padding::gameOver()
{
    for(int i = 0; i < cells.size(); i++)
    {
        cells[i].setEnabled(false);
        if((cells[i].hasMine()) && (!cells[i].getHasBeenClicked()))
        {
            cells[i].clicked();
        }
    }
}

int Padding::countMinesAround(Cell*)
{
    int minesCounter = 0;
    for(int i = 0; i < cells.size(); i++)
    {
        qDebug() << QString::number(cells[i].getX());
        if(((x - cells[i].getX() == 0) || (x - cells[i].getX() == 1) || (x -
            cells[i].getX() == -1)) && ((y - cells[i].getY() == 0) || (y -
            cells[i].getY() == 1) || (y - cells[i].getY() == -1)) &&
            (cells[i].hasMine()))
        {
            minesCounter++;
        }
    }
    return minesCounter;
}

void Padding::triggerChainReactionAround(Cell*)
{
    for(int i = 0; i < cells.size(); i++)
    {
        if(((x - cells[i].getX() == 0) || (x - cells[i].getX() == 1) || (x -
            cells[i].getX() == -1)) && ((y - cells[i].getY() == 0) || (y -
            cells[i].getY() == 1) || (y - cells[i].getY() == -1)) &&
            (!cells[i].getHasBeenClicked()))
        {
            cells[i].clicked();
        }
    }
}

很抱歉整件事花了多长时间,但我无法缩短它,因为我找不到导致错误的原因。另外请忽略任何 TODO 或任何被注释掉的行,我忘了删除它们。请帮忙!

最佳答案

当你转发声明一个类型时,你只能使用指针引用到那个类型对象,所以padding.h中的这一行几乎没有编译:

std::vector<Cell> cells;

我想编译器的提示来自于它试图决定如何构建/销毁 vector 中的 Cell 对象。为此,它需要有关类型的信息,通常来自类型声明(即头文件)。

关于c++ - 不完整类型的无效使用 "class",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48139121/

相关文章:

c++ - 嵌套在函数中的函数声明的命名空间

c++ - 什么时候私有(private)构造函数不是私有(private)构造函数?

c++ - 带有boost的C++中的unicode字符串

c++ - 使用调试器单步执行程序需要很长时间

qt - QAudioRecorder检测到用户不说话并停止

c++ - 打破工厂模式中的循环依赖

c++ - 如何在不重复代码的情况下使用 if-constexpr?

c++ - 读取 http 请求 header (Qt/c++)

qt - 我们如何连接带有不同参数的信号和插槽?

c++ - 如何打破这种循环类型定义?