0

I'm having trouble creating a function that returns my own struct.

Header:

    #ifndef FOOD_H
    #define FOOD_H
    #include <string>

    class Food
    {
    public:
        Food();
        ~Food();
    public:
        struct Fruit {
            std::string name;

        };
        struct Person {
            Fruit favorite;
            Fruit setFavorite(Fruit newFav);
        };

    public:
        Fruit apple;
        Fruit banana;

        Person Fred;
    };
    #endif

CPP:

    #include "Food.h"

    Food::Food()
    {
    }

    Food::~Food()
    {
    }

    Fruit Food::Person::setFavorite(Fruit newFav)
    {
        return newFav;
    }

Main:

    #include "Food.h"
    #include <iostream>

    int main() {
        Food fd;    
        fd.Fred.favorite = fd.Fred.setFavorite(fd.apple);
        std::cout << fd.Fred.favorite.name;
        system("pause");
    }

My errors are:

E0020 identifier "Fruit" is undefined Food.cpp 11

E0147 declaration is incompatible with "Food::Fruit Food::Person::setFavorite(Food::Fruit newFav)" (declared at line 17 of Food.h) Food.cpp 11

How do I fix these and is there a better way to write this code?

O'Neil
  • 3,790
  • 4
  • 16
  • 30
Mimi
  • 3
  • 2
  • 2
    The error message speaks for itself: `Fruit` => `Food::Fruit` – O'Neil Jan 08 '18 at 03:19
  • I don't know what it's telling me is incompatible with what or how to fix it. – Mimi Jan 08 '18 at 03:33
  • Compare your code with the declaration in the error message. This is what the compiler expects. – O'Neil Jan 08 '18 at 03:34
  • Okay got it. I wasn't sure how to read the error. Thank you so much. – Mimi Jan 08 '18 at 03:37
  • 1
    `fd.Fred.favorite = fd.Fred.setFavorite(fd.apple);` is a bit weird. `setFavorite` does not do what one would expect from a setter function: It doesn't set `Food::Person::favorite`. I would expect `fd.Fred.setFavorite(fd.apple);` to `favorite = newFav;` and return nothing. – user4581301 Jan 08 '18 at 03:38
  • Not to mention the member `Person Fred` inside `Food`. – O'Neil Jan 08 '18 at 03:43
  • Yeah, I made this simple example quickly. The actually issue was in a larger project – Mimi Jan 08 '18 at 03:44
  • True. While there is a case for people to be food, in this case it looks like `Person` should be independent of `Food`. – user4581301 Jan 08 '18 at 03:45

2 Answers2

5
identifier "Fruit" is undefined

This error says that there is no definition for Fruit.

You have defined a class Fruit that is nested within Food. Therefore the fully qualified name of the class is Food::Fruit as can be seen from the other error message:

declaration is incompatible with "Food::Fruit Food::Person::setFavorite(Food::Fruit newFav)"
                                  ^^^^^^^^^^^

This error message tells you that the declaration Food::Person::setFavorite(Fruit newFav) is incompatible because that function is supposed to return Food::Fruit rather than Fruit (which is something that doesn't have definition).


Fruit can be used to refer to Food::Fruit within the context of the class Food. The definition of this function is outside of the class, so it is not within the context. It is not until the name of the function (Food::Person::setFavorite) that the context is established. You could use a trailing return type to avoid using the fully qualified type:

auto Food::Person::setFavorite(Fruit newFav) -> Fruit
eerorika
  • 232,697
  • 12
  • 197
  • 326
1

In addition to the accepted answer, OP's class design could also be improved in my opinion. It seems that OP wants to create a fruit class which should have a is-a relationship with food class. Making it a member of food class doesn't seem right to me. Same thing applies to Person class which should be a separated class instead of being a member of food.

#include <string>

class Food
{
    std::string m_name;
        // other stuffs...
};

class Fruit : public Food
{
    // unique fruit members and functions...
};

class Person
{
    Fruit m_favorite;

public:
    void SetFavorite(Fruit favorite);
};

void Person::SetFavorite(Fruit favorite)
{
    m_favorite = favorite;
}

int main()
{
    Fruit apple;
    Person fred;
    fred.SetFavorite(apple);

    return 0;
}
  • Semi-related: No violations here, but be careful with proceeding underscores as they can mean something. [What are the rules about using an underscore in a C++ identifier?](https://stackoverflow.com/questions/228783/what-are-the-rules-about-using-an-underscore-in-a-c-identifier). If you never use a preceding underscore you don't have to care when it's legal or not. – user4581301 Jan 08 '18 at 04:15
  • Is it ok to use succeeding underscore to indicate a member? – Terrence Liao Jan 08 '18 at 04:22
  • You are fine. A single preceding underscore inside a class (or anywhere but the global namespace) is safe. Take it outside the class and you are tempting fate. Take a read of the link in my first comment. It covers all of the rules. – user4581301 Jan 08 '18 at 04:29