Thread: Ouside declaration of a nested struct/class

  1. #1
    Registered User
    Join Date
    May 2008
    Posts
    115

    Ouside declaration of a nested struct/class

    Hello, why does this code with a nested struct compile, whereas moving the nested struct definition of Motor outside of the Car (commented out) and deleting the inside declaration produces an error? And how to fix this. Thank you very much for your help!

    Code:
    struct Gauge
    {
    	int Dial;
    	Gauge(int dial) : Dial(dial) {}
    };
    
    struct Car
    {
    	struct Motor : Gauge
    	{
    		Motor(int dial) : Gauge(dial) {}
    	};
    	Motor Diesel;
    	Car(int gauge) : Diesel(gauge) {}
    };
    
    /*
    struct Car::Motor : Gauge
    {
    	Motor(int dial) : Gauge(dial) {}
    };
    */

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    If you want Motor to be nested inside Car, then what you did was correct. I don't think you can move the definition of Car::Motor out of Car, though you could try that with a forward declaration of Motor in Car to see if it works.

    Oh, but you declare a member object of Motor in Car. Even if you could move the definition of Motor outside of Car by forward declaring it in Car, you cannot then declare an object of Motor in Car because you need the definition of a class to declare an object of the class, not merely a forward declaration. Consequently, what you want to do cannot be done either way, so you should stick with what you have now.

    Of course, it may also be plausible that Motor shouldn't be nested in Car in the first place, in which case just defining it before Car would suffice.
    Last edited by laserlight; 09-19-2019 at 05:39 PM.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #3
    Registered User
    Join Date
    May 2008
    Posts
    115
    Quote Originally Posted by laserlight View Post
    f course, it may also be plausible that Motor shouldn't be nested in Car in the first place, in which case just defining it before Car would suffice.
    OK, thank you for this explanation. I am nesting Motor in Car because I want Motor to use methods of Car:

    For example:

    Code:
    struct Motor : Gauge
    {
    	Motor(int dial) : Gauge(dial) {}
    	void DoSomethingOnCar(Car& car);
    };
    for example, with an outside declaration

    Code:
    void Car::Motor::DoSomethingOnCar(Car& car)
    Maybe there is another way to give Motor access to methods in Car and declare it. Would some trick with friend class, or friend do the trick?


    P.S: Accidentally deleted my post when editing

  4. #4
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Given a Car object, you can already invoke the public member functions of the Car object from within member functions of the Motor class, without nesting or friendship. Are you sure that Motor needs to access the internals of Car, especially since you're using the struct keyword (public by default) rather than the class keyword (private by default)?
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  5. #5
    Registered User
    Join Date
    May 2008
    Posts
    115
    Quote Originally Posted by laserlight View Post
    Given a Car object, you can already invoke the public member functions of the Car object from within member functions of the Motor class, without nesting or friendship. Are you sure that Motor needs to access the internals of Car, especially since you're using the struct keyword (public by default) rather than the class keyword (private by default)?
    I think I have not explained it properly in my last post. I apologize for this.

    The issue I have is this:
    Code:
    struct Car
    {
        struct Motor : Gauge
        {
            Motor(int dial) : Gauge(dial) {}
            void MotorFunction() {};
        };
        Motor Diesel;
        Car(int gauge) : Diesel(gauge) {}
        void CarFunction() {};
    };
    MotorFunction needs to call CarFunction, which then does something on Car. Moving struct Motor outside of Car precludes MotorFunction from calling CarFunction.

  6. #6
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by serge
    MotorFunction needs to call CarFunction, which then does something on Car. Moving struct Motor outside of Car precludes MotorFunction from calling CarFunction.
    No, it doesn't. What you need to do is to have the Motor object or member function be able to refer to a Car object, e.g., through a reference parameter.

    Note that this holds true even if you nest Motor in Car: the Motor member function still needs a way to refer to a Car object to call CarFunction. However, as a nested class Motor would have access to the internals of Car.
    Last edited by laserlight; 09-20-2019 at 07:36 AM.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  7. #7
    Registered User
    Join Date
    May 2008
    Posts
    115
    Here is a full example the definition that does not work, I guess, because of the Motor declaration in Car. I don't see how an external definition can work. Error: "Unknown type name 'Motor' Motor Diesel;

    Code:
    struct Gauge
    {
    	int Dial;
    	Gauge(int dial) : Dial(dial) {}
    };
    
    struct Car
    {
    	int Foo;
    	/*struct Motor : Gauge
    	{
    		Motor(int dial) : Gauge(dial) {}
    		void MotorFunction(int increment, Car& car) { car.CarFunction(increment); }
    	};*/
    	Motor Diesel;
    	Car(int foo, int gauge) : Foo(foo), Diesel(gauge) {}
    	int CarFunction(int increment) { return Foo += increment; }
    };
    
    struct Car::Motor : Gauge
    {
    	Motor(int dial) : Gauge(dial) {}
    	void MotorFunction(int increment, Car& car) { car.CarFunction(increment) }
    };
    
    int main()
    {
    	Car A(1, 2);
    	A.Diesel.MotorFunction(5, A);
    	std::cout << A.Foo << std::endl;
    	return 0;
    }

  8. #8
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Here is how it might be done:
    Code:
    #include <iostream>
    
    struct Gauge
    {
        explicit Gauge(int dial) : Dial(dial) {}
    
        int Dial;
    };
    
    struct Car;
    
    struct Motor : Gauge
    {
        explicit Motor(int dial) : Gauge(dial) {}
    
        void MotorFunction(int increment, Car& car);
    };
    
    struct Car
    {
        Car(int foo, int gauge) : Foo(foo), Diesel(gauge) {}
    
        int CarFunction(int increment)
        {
            return Foo += increment;
        }
    
        int Foo;
        Motor Diesel;
    };
    
    void Motor::MotorFunction(int increment, Car& car)
    {
        car.CarFunction(increment);
    }
    
    int main()
    {
        Car A(1, 2);
        A.Diesel.MotorFunction(5, A);
        std::cout << A.Foo << std::endl;
        return 0;
    }
    Notice that:
    • I declared the Gauge and Motor constructors to be explicit since they take a single parameter, and you probably don't want an implicit conversion through those constructors.
    • I forward declared Car before defining Motor because MotorFunction has a Car& parameter.
    • I defined MotorFunction after defining Car because MotorFunction calls CarFunction, so the Car class must be defined before MotorFunction can be defined.
    • As a matter of purely subjective style, I moved the member variable declarations to the end of the class definitions. This is because if you do make use of private access, typically we would place the members with public access first to indicate that those form the interface, whereas the members with private access tend to be placed towards the end as they are implementation detail.

    I note that in your example, you aren't actually using the Dial member inherited from Gauge.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  9. #9
    Registered User
    Join Date
    May 2008
    Posts
    115
    This is awesome, thank you! I knew there is a trick to pulling that struct outside. Yes, Dial member was not used, sorry about that. Initially I thought I would need it to demonstrate the issue.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 4
    Last Post: 09-03-2018, 06:46 PM
  2. typedef struct vs struct declaration error in code
    By shaswat in forum C Programming
    Replies: 3
    Last Post: 07-25-2016, 06:45 AM
  3. Can Nested class access parent class's private member?
    By meili100 in forum C++ Programming
    Replies: 4
    Last Post: 06-05-2009, 08:42 AM
  4. Replies: 2
    Last Post: 04-06-2005, 07:25 AM
  5. Replies: 4
    Last Post: 12-12-2002, 02:32 PM

Tags for this Thread