引用结构中的另一个结构,其中第二个结构也引用第一个结构

时间:2012-03-27 15:18:53

标签: 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将是未声明的struct

解决这个问题的正确方法是什么?

编辑我在阅读了这个问题的答案之后向前宣布了年份并将年份放在年份之前,但我仍然遇到问题,因为我的原始帖子中没有包含这个功能因为我认为这不是问题的一部分,所以我编辑了我的代码以使其更加完整。

5 个答案:

答案 0 :(得分:2)

我认为你可以像这样向前宣布:

// Declare type year, since we need it to create a pointer
// We can finish the type later
struct Year;

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]; // We need to know how big Month is here
};

它起作用的原因是编译器在使用它们时不需要知道任何类型(因为它们是指针),它只需要知道那些类型存在。

编辑:我实际上不得不在年前移动Month,因为它需要struct Month months[12];的信息

答案 1 :(得分:2)

首先移动Month的定义,然后移动前向声明Year

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];
}

对于数月的数组,Year需要Month的完整定义。

Month中,您只有指向Year的指针,因此前向声明就足够了。

请注意,在C ++中,struct关键字是多余的 - 您可以使用struct Year *year;替换Year *year;

答案 2 :(得分:2)

您的代码可以通过多种方式进行改进,如下所示。

#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 ?答:它不能,因为它甚至不知道月的大小。

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

你的代码还需要一些分号,加上一个标准的包含标题,我添加了这两个分号。

祝你好运。

更新以回应以下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);
    }
}

答案 3 :(得分:2)

struct Year;

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的数组(非动态),因此必须知道Month的确切大小。


OP编辑问题后

编辑

您遇到的问题很容易解决。 http://ideone.com/n4NYy - 这是你的代码被复制和编译;正如您所看到的,问题是Year在实现函数时是不完整的类型;只需将其移到结构声明之外,声明Year之后。这是在C ++中的struct / class体内不保持声明和实现的原因之一。

答案 4 :(得分:1)

将setDayNumber()移出struct的声明: 日:: setDayNumber(...) { }