-1

I have a Class A, in the class there is some important member (lets call it someVeryImportantNumber) and also objects of class B. In class B there are objects of class C and so on..., similar to a tree structure (could be 4, 10, or 20 levels of such objects.)

How could i get access to someVeryImportantNumber from the bottom of the hierarchy (to access someVeryImportantNumber from class D).

I was thinking about passing the number down the hierarchy, but this seems not very effective approach when i have lets say 10 or more of levels hierarchy.

Is there some smarter way to do it? I looked at dependency injection but it is not the way to go for me...

Any suggestions? Thank you...

class D {
public:
    void foo() {
        // need to use someVeryImportantNumber here
    }
}

class C {
public:
    D d1;
    D d2;
    D d3;
}

class B {
public:
    C c1;
    C c2;
}

class A {
public:
    int someVeryImportantNumber = 1234;
    B b;
}

int main() {
    A a;
    return 0;
}
  • 1
    On which `A` should `D` be accessing the `someVeryImportantNumber` of? I understand that you have a setup where `A` has a `B` which has a `C` which has a `D`... but what if someone creates some `D` outside of your hierarchy? Then which `A` should your `foo()` be looking at? Or what if someone has a `C` or a `B` outside of your hierarchy? I think we need more information on what exactly you're trying to do here. – scohe001 Jan 12 '21 at 18:57
  • You can pass a reference down the hierarchy through the constructors. But without knowing what the real use case and role of `someVeryImportantNumber`is, it's hard to tell what you really need, or if you're chasing a XY problem. – πάντα ῥεῖ Jan 12 '21 at 18:59
  • someVeryImportantNumber could be some DatabaseConnector, or some kind of general settings... – Miroslav Krajcir Jan 12 '21 at 19:03
  • @Miroslav that sounds like the kind of thing you'd want a Singleton for (ie: https://stackoverflow.com/q/1008019/2602718) – scohe001 Jan 12 '21 at 19:03
  • schohe001: the objects exist only the the hierarchy, because only class A can create object of class B and only class B can create object of class C etc... – Miroslav Krajcir Jan 12 '21 at 19:04
  • yes singelton is for sure a way to go here, but i dont want to expose the someVeryImportantNumber to the whole program, just to the hierarchy structure... – Miroslav Krajcir Jan 12 '21 at 19:05
  • If you ***must have*** an `A` to create a `B` (and so on...), then why not have `B` take an `A` or an `A` pointer in the constructor and then store it? – scohe001 Jan 12 '21 at 19:05
  • @scohe001 yes i could do it, but imagine object of class C being created somewhere else and just pointer of the object is stored in class B, so passing pointers in constructors down the way it out of option... – Miroslav Krajcir Jan 12 '21 at 19:08
  • Wait, what? I thought you said "only class B can create object of class C." Are you now saying `C` instances can be created outside of the hierarchy? Because then we're back to my initial comment--on which `A` should a `D` be accessing your number? – scohe001 Jan 12 '21 at 19:11
  • 1
    @MiroslavKrajcir Just to note: There's no _"hierarchy"_, that's just a bunch of unrelated classes, which share a common parameter. – πάντα ῥεῖ Jan 12 '21 at 19:15

2 Answers2

1

You can use a reference to avoid copying that someVeryImportantNumber, and pass it through the constructors:

class D {
    const int& someVeryImportantNumber_;
public:
    D(const int& someVeryImportantNumber) : someVeryImportantNumber_(someVeryImportantNumber) {}
    void foo() {
        // need to use someVeryImportantNumber here
    }
}

class C {
public:
    C(const int& someVeryImportantNumber) 
     : d1(someVeryImportantNumber), d2(someVeryImportantNumber), d3(someVeryImportantNumber) {}
    D d1;
    D d2;
    D d3;
}

class B {
public:
    B(const int& someVeryImportantNumber) 
     : c1(someVeryImportantNumber), c2(someVeryImportantNumber) {}
    C c1;
    C c2;
}

class A {
public:
    A() : b(someVeryImportantNumber) {}
    int someVeryImportantNumber = 1234;
    B b;
}

int main() {
    A a;
    return 0;
}
πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
  • thanks for the suggestion, i understand it could work like this, but imagine like 5 such important numbers and 10 levels of hierarchy, this would be mess it think... – Miroslav Krajcir Jan 12 '21 at 19:19
  • 1
    @MiroslavKrajcir Put those numbers together in a common configuration class, you setup once and pass everywhere it's needed. Or do the same using it's "dirty little brother", and provide that configuation as a _Singleton_, which instance would be accessible from everywhere. – πάντα ῥεῖ Jan 12 '21 at 19:23
1

You cannot do what you're asking. The reason is simple: in your example, D is contained in C as 3 separate instances, and there is no way to tell, from an object of type D, which instance it belongs to (d1, d2, or d3).

On the other hand, you could access the container instance through something like container_of macro, provided that you also know which instance D belongs to. See https://radek.io/2012/11/10/magical-container_of-macro/. Notice that container_of is used in C but it works in C++ as well.

For instance, if you know that your D is accessed from C::d1, you could use container_of(this, C, d1) to access the instance of C and then reiterate the procedure to access B and then A.

But remember, there is no way to know at run time which one of the 3 instances of D your this pointer refers to, unless you somehow encode the information in your classes.

Mario Demontis
  • 469
  • 3
  • 11
  • thanks, my idea was to store pointer of class A (or the original creator on top of the hierarchy) in each class D object, so i could have access to members of object A from object D... – Miroslav Krajcir Jan 12 '21 at 19:23