c++ - 在结构中引用另一个结构,其中第二个结构也引用第一个结构

标签 c++ struct

编辑:阅读粗体行以找到我遇到问题的地方。看了答案改了代码还是报错

我是 C++ 的新手,我正在测试一些东西以了解如何使用该语言,我遇到了这种情况:

我有一个 struct,它创建一个指向另一个 struct 的指针。另一个 struct 反过来创建一个指向首先实例化它的 struct 的指针。

这是一个简单的例子,可以更好地解释我的意思(这部分已经更改,添加了代码,粗体行是我遇到问题的地方):

#include <string>

using namespace std;

struct Month;
struct Year;

struct Day{
    unsigned int day, dayNumber;
    string name;

    Day(){}

    void setDayNumber(unsigned int dayNumber){
        this -> dayNumber = dayNumber;

        switch(dayNumber){
        case 0:
            name = "Sunday";
            break;
        case 1:
            name = "Monday";
            break;
        case 2:
            name = "Tuesday";
            break;
        case 3:
            name = "Wednesday";
            break;
        case 4:
            name = "Thursday";
            break;
        case 5:
            name = "Friday";
            break;
        case 6:
            name = "Saturday";
            break;
        }
    }
};

struct Month{
    string name;
    unsigned int monthLength, monthNumber;
    Month *previousMonth, *nextMonth;
    Year *year;
    Day *days;

    Month(unsigned int monthNumber, Year *year){
        this -> monthNumber = monthNumber;

        switch(monthNumber){
        case 0:
            name = "January";
            break;
        case 1:
            name = "February";
            break;
        case 2:
            name = "March";
            break;
        case 3:
            name = "April";
            break;
        case 4:
            name = "May";
            break;
        case 5:
            name = "June";
            break;
        case 6:
            name = "July";
            break;
        case 7:
            name = "August";
            break;
        case 8:
            name = "September";
            break;
        case 9:
            name = "October";
            break;
        case 10:
            name = "November";
            break;
        case 11:
            name = "December";
            break;
        }

        previousMonth = NULL;
        nextMonth = NULL;
        this -> year = year;
    }

    void createDays(){
        if(name == "January" || name == "March" || name == "May" || name == "July" || name == "August" || name == "October" || name == "December")
            monthLength = 31;
        else if(name != "February")
            monthLength = 30;
        else{
            **if(year -> isLeapYear() == true)** //This line is problematic, see below the code to see what the compiler says
                monthLength = 29;
            else 
                monthLength = 28;
        }

        days = new Day[monthLength];

        for(unsigned int i = 0; i < monthLength; i++){
            days[i].day = i+1;

            if(i == 0 && previousMonth == NULL)
                days[i].setDayNumber(2);
            else if(i == 0)
                days[i].setDayNumber(previousMonth -> days[previousMonth -> monthLength - 1].dayNumber);
            else
                days[i].setDayNumber(days[i-1].dayNumber);
        }
    }
};

struct Year{
    unsigned int year;
    Year *previousYear, *nextYear;
    Month *months;

    Year(unsigned int year){
        this -> year = year;
        previousYear = NULL;
        nextYear = NULL;
    }

    void createMonths(){
        Month *currentMonth = months;
        unsigned int monthNumber;

        for(unsigned int i = 0; i < 12; i++){
            months = new Month(i, this);
        }

        while(currentMonth != NULL){
            monthNumber = currentMonth -> monthNumber;

            if(monthNumber == 0 && previousYear != NULL){
                months[monthNumber].previousMonth = &(previousYear -> months[11]);
                months[monthNumber].nextMonth = &(months[monthNumber+1]);
            }
            else if(monthNumber == 11 && nextYear != NULL){
                months[monthNumber].nextMonth = &(nextYear -> months[0]);
                months[monthNumber].previousMonth = &(months[monthNumber-1]);
            }
            else{
                if(monthNumber != 0)
                    months[monthNumber].previousMonth = &(months[monthNumber-1]);
                if(monthNumber != 11)
                    months[monthNumber].nextMonth = &(months[monthNumber+1]);
            }
        }

        currentMonth = months;

        while(currentMonth != NULL){
            currentMonth -> createDays();
            currentMonth = currentMonth -> nextMonth;
        }
    }

    bool isLeapYear(){
        if(year % 4 == 0 && (year % 100 != 0 || year % 400 == 0))
            return true;
        else
            return false;
    }
};

编译器输出的信息如下:

pe_019.cpp(107): error C2027: use of undefined type 'Year'
pe_019.cpp(10) : see declaration of 'Year'
pe_019.cpp(107): error C2227: left of '->isLeapYear' must point to class/struct/union/generic type

显然,还有更多,但在 Year 中,我使用了一个 struct Month 数组,在 Month 中,有指向其父 Year 的指针。 (与 Day 相同,具有父级 Month)。

当我尝试编译时,编译器说我正在使用未定义的 struct 'Month'Month* 的大小未知,等等。

我很确定这是因为在声明之前使用了 Month,但我不能先声明它,因为 Year 将是未声明的 结构

正确的做法是什么?

编辑:在阅读了这个问题的答案后,我提前声明了 Year 并将 Month 放在 Year 之前,但是由于我没有包含在原始帖子中的功能,我仍然遇到问题因为我认为这不是问题的一部分,所以我编辑了我的代码以使其更完整。

最佳答案

可以通过以下几种方式改进您的代码。

#include <string>
using std::string;

struct Year;
struct Day;

struct Month{
    string name;
    unsigned int monthLength;
    struct Month *previousMonth, *nextMonth;
    struct Year *year;
    struct Day *days;
};

struct Year{
    unsigned int year;
    struct Year *previousYear, *nextYear;
    struct Month months[12];
};

这个修复的最重要的问题是,尽管 Month 的定义只指定了一个指向 Year 的指针,Year 的定义> 实际上包括整个。让我们考虑一下,因为这里有一些重要的东西需要学习。如果编译器还不知道 Month 是什么,它如何决定如何在内存中布置 Year?回答:它不能,因为它甚至不知道 Month 的大小。

仅仅包含一个指针不会带来这个问题,因为编译器知道指针的大小,即使它不知道所指向对象的类型。

您的代码还需要一些分号,以及一个标准的 header 包含,这两者都是我添加的。

祝你好运。

更新以响应下面 OP 的评论: 修改后的代码发布在下面。请注意,它以及如何延迟受影响函数的定义,直到函数所需的类型被完全定义为止。

(顺便说一句,如果您对我的想法感兴趣,使用命名空间 std 几乎从不推荐。它破坏了 C++ 有用的命名空间机制。)

#include <string>

using namespace std;

struct Month;
struct Year;

struct Day{
    unsigned int day, dayNumber;
    string name;

    Day(){}

    void setDayNumber(unsigned int dayNumber){
        this -> dayNumber = dayNumber;

        switch(dayNumber){
        case 0:
            name = "Sunday";
            break;
        case 1:
            name = "Monday";
            break;
        case 2:
            name = "Tuesday";
            break;
        case 3:
            name = "Wednesday";
            break;
        case 4:
            name = "Thursday";
            break;
        case 5:
            name = "Friday";
            break;
        case 6:
            name = "Saturday";
            break;
        }
    }
};

struct Month{
    string name;
    unsigned int monthLength, monthNumber;
    Month *previousMonth, *nextMonth;
    Year *year;
    Day *days;

    Month(unsigned int monthNumber, Year *year){
        this -> monthNumber = monthNumber;

        switch(monthNumber){
        case 0:
            name = "January";
            break;
        case 1:
            name = "February";
            break;
        case 2:
            name = "March";
            break;
        case 3:
            name = "April";
            break;
        case 4:
            name = "May";
            break;
        case 5:
            name = "June";
            break;
        case 6:
            name = "July";
            break;
        case 7:
            name = "August";
            break;
        case 8:
            name = "September";
            break;
        case 9:
            name = "October";
            break;
        case 10:
            name = "November";
            break;
        case 11:
            name = "December";
            break;
        }

        previousMonth = NULL;
        nextMonth = NULL;
        this -> year = year;
    }

    void createDays();

};

struct Year{
    unsigned int year;
    Year *previousYear, *nextYear;
    Month *months;

    Year(unsigned int year){
        this -> year = year;
        previousYear = NULL;
        nextYear = NULL;
    }

    void createMonths(){
        Month *currentMonth = months;
        unsigned int monthNumber;

        for(unsigned int i = 0; i < 12; i++){
            months = new Month(i, this);
        }

        while(currentMonth != NULL){
            monthNumber = currentMonth -> monthNumber;

            if(monthNumber == 0 && previousYear != NULL){
                months[monthNumber].previousMonth = &(previousYear -> months[11]);
                months[monthNumber].nextMonth = &(months[monthNumber+1]);
            }
            else if(monthNumber == 11 && nextYear != NULL){
                months[monthNumber].nextMonth = &(nextYear -> months[0]);
                months[monthNumber].previousMonth = &(months[monthNumber-1]);
            }
            else{
                if(monthNumber != 0)
                    months[monthNumber].previousMonth = &(months[monthNumber-1]);
                if(monthNumber != 11)
                    months[monthNumber].nextMonth = &(months[monthNumber+1]);
            }
        }

        currentMonth = months;

        while(currentMonth != NULL){
            currentMonth -> createDays();
            currentMonth = currentMonth -> nextMonth;
        }
    }

    bool isLeapYear(){
        if(year % 4 == 0 && (year % 100 != 0 || year % 400 == 0))
            return true;
        else
            return false;
    }
};

void Month::createDays(){
    if(name == "January" || name == "March" || name == "May" || name == "July" || name == "August" || name == "October" || name == "December")
        monthLength = 31;
    else if(name != "February")
        monthLength = 30;
    else{
        if(year -> isLeapYear() == true)
            monthLength = 29;
        else
            monthLength = 28;
    }

    days = new Day[monthLength];

    for(unsigned int i = 0; i < monthLength; i++){
        days[i].day = i+1;

        if(i == 0 && previousMonth == NULL)
            days[i].setDayNumber(2);
        else if(i == 0)
            days[i].setDayNumber(previousMonth -> days[previousMonth -> monthLength - 1].dayNumber);
        else
            days[i].setDayNumber(days[i-1].dayNumber);
    }
}

关于c++ - 在结构中引用另一个结构,其中第二个结构也引用第一个结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9892484/

相关文章:

c++ - 有没有优化两个BigNums的乘法的好方法?

c - 正确释放动态分配的结构

c++ - 如果你向前移动如何改变屏幕,如果你向后移动如何看到旧的东西?

c++ - 当名称出现在函数的 declarator-id 之前时,查找规则是什么?

C++ 虚拟方法的部分模板特化

c++ - OpenCV 中的非最大抑制

c - 列表中的学生 ID 未打印出来

c++ - 所有权以及如何避免 shared_ptr

c - 'struct x' 在参数列表中声明

c - Objective-C 2.0 垃圾收集是否收集 C 结构?