0

With a subfunction I mean that given a class A and instance a, I can call

a.control.fire();

Where control is some type of struct containing functions. However, an additionall requirement is that fire() can access variables of a. I have tried the following:

#pragma once

using namespace std;

class A {
public:
    double c;

    struct Controller {
        double fire () { return c * 2};
    };

    Controller control;

    A();
};

Now I can indeed call a.control.fire() but it gives an error on trying to access c. How can I solve this?

Thomas Wagenaar
  • 6,489
  • 5
  • 30
  • 73

2 Answers2

-1

Nested classes on cpprefrence.com

Like any member of its enclosing class, the nested class has access to all names (private, protected, etc) to which the enclosing class has access, but it is otherwise independent and has no special access to the this pointer of the enclosing class.

C++ does not create an instance of the inner class when the outer class is created. Nor does the inner class gain any variables which allow it to use the outer classes variables. The classes have to explicitly declare access to each other (for example by instantiations, references or pointers).

So the Controller needs 2 things :

  • the reference to the variable c or an instantiation of it's class: double& ref_c or A& a
  • a constructor which initializes ref_c or a

Then in A's constructor controller needs to be initialized with c or *this (aggregate initialization can also be used).


Example:

class Outer // Enclosing
{
public:
    double c;

    struct Inner // Nested
    {
        const Outer& a;

        double fire() const { return a.c * 2; };
    };

    Inner control { *this };

    Outer();
};
Robert Andrzejuk
  • 5,076
  • 2
  • 22
  • 31
-2

There are two watertight containers inside of class A: double c and struct Controller. From inside of one you cannot get to the other. The rule in C++ layers of abstraction is that you cannot go from the inside out. You can only go from the outside in. Controller::fire() can only see stuff inside the Controller itself. It has no knowledge of the outside world.

You can improve your code by getting rid of the Controller all together. It is a "wall" which prevents your function from seeing the double c because it is sitting inside that wall:

    #pragma once

using namespace std;

class A {
public:
    double c;

    double fire () { return c * 2};


    A();
};

The other way to do it would be to provide some "door" through the "wall", some kind of mechanism to get the double c into the Controller to make it visible to the double fire(). I mean declare a constructor Controller::Controller() and pass a pointer in.

#pragma once

using namespace std;

class A {
public:
    double c;

    struct Controller {
        Controller(double* ptr) : c_ptr(ptr) {}
        double * c_ptr;
        double fire () { return *c_ptr * 2};
    };

    Controller control(&c);

    A();
};

As mentioned in another answer, you can also use references in C++. That would actually be even better in this situation.

#pragma once

using namespace std;

class A {
public:
    double c;

    struct Controller {
        Controller(double& input) : c(input) {}
        double& c;
        double fire () { return c * 2};
    };

    Controller control(c);

    A();
};
Galaxy
  • 2,363
  • 2
  • 25
  • 59