0

Imagine the next problem. I want a class Map. Every Map instances contains a list of Locations. I also want that every Location knows of the Map that owns him. (Could this hinder encapsulation?) In Python I can use type hints, with no problem. I can define both classes in either order.

from __future__ import annotations
class Map:
    def __init__(self):
        self.locations: list[Location]
        self.locations = []
class Location(self, ):
    def __init__(self, owner: Map):
        self.owner = owner

This hinders encapsulation, I guess. But in Python, aren't we all adults according to the philosophy of the language? This helps me a lot. If the Location child can access the parent, I can change something in the Location and the Parent can know.

Can I use this kind of design in C++? It this recommended? Can a child have a reference of his father? Can I declare a child class with knowledge of its parent AT THE SAME TIME that the parent know of its children?

I've learned C++ by myself and I never read about it.

Mert Mint
  • 29
  • 4
  • Maybe you want the CRTP pattern? https://stackoverflow.com/questions/4173254/what-is-the-curiously-recurring-template-pattern-crtp – ShadowMitia Nov 29 '21 at 16:00
  • 3
    Forward declaration would be needed for circular dependencies. – Jarod42 Nov 29 '21 at 16:01
  • 1
    Encapsulation? C++ don't need no stinking encapsulation. It's just highly recommended. This isn't an encapsulation problem, though. It's a [Single-Pass Compiler](https://en.wikipedia.org/wiki/One-pass_compiler) artifact. – user4581301 Nov 29 '21 at 16:16
  • 1
    encapsulation is no black or white. Some ppl even use getters and setters and call that encapsulation. I don't see how encapsulation prevents you to do what you want – 463035818_is_not_an_ai Nov 29 '21 at 16:18

2 Answers2

3

There is no problem with doing this in C++. You just need to forward declare either the map class or the location class.

As far as encapsulation goes, it isn't really an issue if Location is just using Map's public interface. If you want Location to not have to use Map's public interface, Map could friend the location class but in that case encapsulation is being violated; it's a matter of taste though. There are no right or wrong answers about this kind of stuff.

Anyway code below:

#include <vector>

class Location;  // <= this is a forward declaration.

class Map {
private:
    std::vector<Location> locations_;
public:
    void insertLocation(float longitude, float lattitude);
};

class Location {
private:
    Map& parent_;
    float longitude_;
    float lattitude_;
public:
    Location(Map& map, float longi = 0.0f, float lat = 0.0f) :
        parent_(map), longitude_(longi), lattitude_(lat)
    {}
};

void Map::insertLocation(float longitude, float lattitude) {
    locations_.emplace_back(*this, longitude, lattitude);
}

int main(void) {
    Map map;
    map.insertLocation(10.0, 40.0);
    return 0;
}
jwezorek
  • 8,592
  • 1
  • 29
  • 46
  • Thank you very much. This example opens a ton of new dessigns. I will try to incorporate this kind of declaration structure. – Mert Mint Nov 29 '21 at 17:03
1

In C++, the class declaration usually goes in the header, and the class methods go in the .cpp file. This is different from Python.

An important consequence is that you can include the parent header in the child .cpp file and vice versa. Hence, the child class methods can use the parent declaration and vice versa.

MSalters
  • 173,980
  • 10
  • 155
  • 350
  • This doesn't help if each class has a member variable that is a pointer to the other class. Then the declaration of class A depends on the declaration of class B, which depends on the declaration of class A, so there is no correct order to include the header files. (See the other answer for a solution to this.) – David Grayson Nov 29 '21 at 16:31