C++ sharing object between two class

Refresh

April 2019

Views

837 time

1


Suppose I have two class: FirstContainer and SecondContainer
They hold the same reference (pass in their constructor) to the class ThirdContainer.
FirstContainer and SecondContainer have the following methods:
- addMemberToThirdContainer
- delMemberOfThirdContainer
- getThirdContainerMembers

When the ThirdContainer is modified, I want the two others to update using getThirdContainerMembers(). For this purpose I use the observer/listener pattern.

ThirdContainer has a list of listener and a method: addNewListener. FirstContainer and SecondContainer register by doing: mThirdContainer.addNewListener(this);

I'm not sure this is the good way to do this, I'm new to oriented object.
What are my other possibilities to achieve something like that ?
I'm not attached to anything I stated, it's just here because I have hard time to explain what I want to do. I hope it's clear. Thanks for the help,
Best,

Edit: What a bout using forward declaration ? I could do something like:

 class ParentContainer {
 public:
     ParentContainer(ThirdContainer&)
     : mFirstContainer(*this), mSecondContainer(*this) { };

     ~ParentContainer(); 

     void addMemberToThirdContainer() {
        mThirdContainer.addMember();
        notify();
     }; 

     void delMemberOfThirdContainer() {
        mThirdContainer.delMember();
        notify();
     };

 private:
     std::vec<int>& getMemberOfThirdContainer() {
        return mThirdContainer.getMember();
     };

     void notify() {
        auto vec = getMemberOfThirdContainer();
        mFirstContainer.update(vec);
        mSecondContainer.update(vec);
     };

     ThirdContainer& mThirdContainer;
     FirstContainer  mFirstContainer;
     SecondContainer mSecondContainer; 
 };

Then in FirstContainer and SecondContainer something like:

 class ParentContainer;

 class FirstContainer {
 public:
      FirstContainer(ParentContainer&);
      ~FirstContainer(); 

      void update(std::vector<int>& vec);

 private:
      ParentContainer& mParentContainer;
 };

In FirstContainer and SecondContainer I will have access to ThirdContainer by doing:
mParentContainer.addMemberToThirdContainer and mParentContainer.DelMemberOfThirdContainer.
And I will get notification. I mean I guess ....

2 answers

0

If you like using libraries, you can use any library that provide Signal/Slot system, like Boost or Qt.

If you don't like libraries, you should try to

  1. Create an interface (in C++, just an abstract class with pure virtual method, onModified for example:

    class ThirdContainerListener {
        public: virtual void onContainerModified() = 0;
        // Virtual: is to make it overridable
        //  = 0: is the C++ way to say "abstract", 
        //         which means this function MUST be overridden.
    };
    
  2. Make a vector of pointers to listeners (to be safe, try to use smart-pointers, like shared_ptr) {This goes inside the ThirdContainer}

    vector<shared_ptr<ThirdContainerListener>> listeners;
    
  3. Make (also inside the ThirdContainer), a function that adds listener, like that

    void addNewListener(shared_ptr<ThirdContainerListener> container) {
        listeners.push_back(container); // Adds the pointer to the listeners
    }
    
  4. Hide your real container, like that

    private: vector<int> list;
    
  5. Make a private function that calls all listeners, to be used LOCALLY

    private: void callAllListeners() {
        // Traverse through all the listeners
        for(shared_ptr<ThirdContainerListener> listener: listeners) {
            // Call each one's overridden function
            listener->onContainerModified();
        }
    }
    
  6. Expose functions that modify your container, those call all listeners, like that

    public: void addData(int d) {
                list.push_back(d);
                callAllListeners();
            }
    
    // Also you could make "removeDataByIndex", "addManyData", etc...
    
  7. Use shared_ptr<ThirdContainer> in both First and Second container, to ensure your classes wouldn't leak memory or point to nothing (dangling pointer)

0

When the ThirdContainer is modified, I want the two others to update using getThirdContainerMembers().

Why? This does not really make much sense to me. Or at least - I don't understand your motivation. Why can't the two containers just get the members when they actually need them, rather than once on every update? Or better yet - why get a copy of the members at all, when you can possibly just keep the members in ThirdContainer and iterate them in there?

Now, you could say "Maybe the iterator gets invalidated during such access". But that's also an issue during the call to getThirdContainerMembers().

ThirdContainer has a list of listener and a method: addNewListener.

I don't like this approach, and would advise you to consider whether you really want to follow it.

I believe it is more fitting for interpreted languages, which have dynamically-typed objects, to which you can add or remove functionality on the fly, or at least they have interpreter/virtual-machine-provided mechanisms for observation and introspection. With such languages, your ThirdContainer doesn't have to be designed in advance to support listeners.

With C++, however, you will have to impose on the encapsulated design of ThirdContainer (or at least - inherit from an existing design), so that it supports listeners). But then, another time you would need to listen on some other event, and you'll again need to subclass or alter the interface of ThirdContainer - no, I'd rather not.

Instead, consider having whoever adds elements to the ThirdContainer be responsible for also updating the FirstContainer and SecondContainer instances which share it; or avoiding updates altogether.