2

I am trying to access the attribute of an "outer" class from a method of an "inner" (local) class but I fail.

This fails to compile

class outer
{
    public:
        std::string name;

        class inner
        {
          public:
            void hello();  
        };

        void dostuff();

};

void outer::inner::hello(){std::cout << "Hello " << name << "\n";}

void outer::dostuff(){inner instanceInner; instanceInner.hello();}


int main()
{
   outer instanceOuter;
   instanceOuter.name = std::string("Alice");
   instanceOuter.dostuff();

   return 0;
}

Compilation Error:

9:21: error: invalid use of non-static data member 'outer::name'
21:53: error: from this location

I don't really want name to be a static member but I don't really mind as for my particular purpose outer is a singleton. So I tried with static std::string name; and got

Compilation Error:

/tmp/ccqVKxC4.o: In function `outer::inner::hello()':
:(.text+0x4b): undefined reference to `outer::name'
/tmp/ccqVKxC4.o: In function `main':
:(.text.startup+0x1f): undefined reference to `outer::name'
collect2: error: ld returned 1 exit status

Can you help me out?

Remi.b
  • 17,389
  • 28
  • 87
  • 168

2 Answers2

3

Your problem lies in your hello() function. name is out of scope here. It is not part of your inner class. Unfortunately your inner class will not have visibility of your outer class and its members, thus this:

void outer::inner::hello(){
    std::cout << "Hello " << name << "\n";
}

will yield an error telling you name cannot be found.

You can do the following:

#include <iostream>
#include <string>

class outer
{
    public:
        static std::string name;

        class inner
        {
          public:
            void hello();  
        };

        void dostuff();

};


std::string outer::name = ""; // This is key. You need to instantiate outer's name somewhere.

void outer::inner::hello(){std::cout << "Hello " << outer::name << "\n";}

void outer::dostuff(){inner instanceInner; instanceInner.hello();}


int main()
{
   outer instanceOuter;
   instanceOuter.name = std::string("Alice");
   instanceOuter.dostuff();

   return 0;
}

Output:

Hello Alice
Santiago Varela
  • 2,199
  • 16
  • 22
  • Thanks for your answer. I can't see any difference between your "hello" and mine (`void outer::inner::hello(){std::cout << "Hello " << name << "\n";}`). Is there something I am misunderstanding? – Remi.b Apr 16 '17 at 19:12
  • I was just pointing out where you error lied and why it was occurring. If you check my edit now you can see a suggestion to manage this @Remi.b – Santiago Varela Apr 16 '17 at 19:13
  • I could just pass `name` to the function. I am trying not to pass it though. The reason is that I have a relatively long code (~1000 lines) and I just wrapped the whole think in an outer class. I would appreciate not having to pass every attribute of the outer class to every function call. Note that passing everything as arguments might eventually decrease performance as well for small function being called repeatedly for which I'd have maybe 5 arguments to pass as reference. It might eventually be impossible to do otherwise (unless calling each attribute via the instance of the outer class) – Remi.b Apr 16 '17 at 19:20
2

Repeating (with small modifications) something I've mentioned in another answer, to a similar recent SO question:

A C++ nested class does not share data with its outer class -- if there were the case, each instance of the inner class would be in a one-to-one relationship with a corresponding instance of an outer class and would thus add no extra functionality. Instead, the main purposes of nested classes are:

  1. Namespace meaning: outer::inner is more meaningful than outer_inner
  2. Depending on the C++ version standard, a nested class has extra visibility of the member objects of instances of the outer class
  3. Maybe others that I'm not aware of

Here is a popular reference question on when/why to use nested classes in C++: Why would one use nested classes in C++?

In your case, the inner class cannot refer to the data name without either a) a specific instance of the outer class whose name will be accessed, or b) a static name that is universal to outer. The first solution requires the inner class to be constructed with a reference to an outer class:

inner (const outer& _o) : o(_o) {}

where o is a private member of type const outer&. Then the hello function be be written

void outer::inner::hello(){std::cout << "Hello " << o.name << "\n";}

Alternatively, if you want to make name static, it is an undefined reference because you must put

std::string outer::name = "bla";

in a compilation unit somewhere, otherwise the static member is not defined.

In either case, however, I worry that you are misusing the nested class. What purpose does it serve in your code? Why must data and member functions be separated between the outer and nested class? Are you sure one class wouldn't serve your purposes better?

Community
  • 1
  • 1
jwimberley
  • 1,696
  • 11
  • 24