Reputation: 35
I have a global class TRK
that has many members and methods. I wanted to organize these by sorting them into different named categories, e.g. Fitting
, such that the namespace of the main class isn't overcrowded. In a perfect world, I would want this example to work:
class TRK
{
public:
// constructors
TRK(...);
...
TRK();
~TRK();
// nested classes
class Fitting;
// and many other methods...
private:
...
};
class TRK::Fitting
{
public:
// constructors/destructor
TRK& trk;
Fitting();
~Fitting();
// and many other methods...
private:
...
};
The key thing here that I need is to be able to:
Instance some TRK
object using one of the TRK
class' constructors, and I need the TRK
constructors to be able to also automatically instantiate accompanying nested classes e.g. Fitting
, for that instance of TRK
. I then need to be able to instantiate/give values to members of these nested classes, within the TRK
constructors. For example, if Fitting
has some member x
, I need to be able to initialize the value for x
for that instance of TRK within the TRK
constructor, given the arguments to the constructor. What I'm unclear on is how exactly to go about this; how and where can I instantiate these nested classes?
Access members of the nested classes from TRK instances and methods, and vice versa. I already can do the latter by passing TRK
by reference to the nest classes, as shown, but I'm not sure how to do the former.
For example, I have methods of Fitting
that need to use members of whatever TRK
instance that that instance of Fitting
was created within. Similarly, I have methods of Fitting
that methods of TRK
need to be able to call.
Should I even be using nested classes for this? I tried using namespaces and inheritance but I couldn't get things to work the way that I wanted. My core issue here is attempting
Upvotes: 2
Views: 1647
Reputation: 7973
If you want the constructor of TRK
to in turn cause the construction of a TRK::Fitting
variable, the definition of TRK::Fitting
must be completely known to it, a forward declaration is not enough. However, once you do that, you can intialize member variables of the nested class type just like you would always do. Here is an example:
class TRK {
class Fitting {
int x;
public:
Fitting(int x): x(x) {}
};
Fitting fitting;
public:
TRK(int y): fitting(y) {}
};
A nested class is just a regular class, only its name is nested. It does not automatically know where the non-static member variables of the parent are. A simple solution is to provide the nested class with a reference to the instance of the parent class, like so:
class TRK {
class Fitting {
TRK &parent;
int x;
public:
Fitting(TRK &parent, int x): parent(parent), x(x) {}
void foo() {
// Use something from the parent class
parent.bar();
}
};
Fitting fitting;
public:
TRK(int y): fitting(*this, y) {}
void bar() {}
};
Another option is to not store a reference to the parent in the child class, but rather to explicitly pass a reference to the parent to every member function of the child class:
class TRK {
class Fitting {
void foo(TRK &parent) {
// Use something from the parent class
parent.bar();
}
};
Fitting fitting;
public:
TRK(int y): fitting(y) {}
void bar() {}
void quux() {
fitting.bar(*this);
}
};
Calling a member function of the child class from the parent class is easy, as shown in TRK::quux()
.
If you want to use inheritance and have the base class be able to call functions in the derived class, then the curiously recurring template pattern can be used, like so:
template <typename Derived>
class TRK {
...
void bar() {}
void quux() {
// We need to static_cast<> ourself to get an object of type Derived
static_cast<Derived>(*this)::foo();
}
};
class Derived: TRK<Derived> {
...
void foo() {
// We can directly call any base class member functions here
bar();
}
}
Upvotes: 2