Home > Software engineering >  How to save an object inside another object in C
How to save an object inside another object in C

Time:02-04

I have 2 classes lets say Class A and Class B,

class A {

public: 
    A(B b);
    B GetB();

private:
    B b;
};

class B {

public:
    B();
    void IncrementCounter();
    int GetCounter();

private:
   int counter = 0;
};

I want to pass an object of type B to class A's constructor and then save this instance of class B in Class A instance. What is the best way to pass class B instance as a parameter, and what is the best way to save class B instance in class A instance.

Note: I do not want to create copies of class B instance, I want A.getB().GetCounter to always be the same as b.GetCounter().

int main(){
   B b;
   A a(b);
   b.IncrementCounter();
   a.getB().IncrementCounter();

   // then b.GetCounter() is same as a.getB().GetCounter() and both = 2

}

I see people using pointers/smart pointer and references/std:reference_wrapper, what is the difference?

CodePudding user response:

Use std::shared_ptr if you don't want copies, example : I assume you are familiar with references, const references and const member functions.

#include <memory>
#include <iostream>

class B
{
public:
    B()
    {
        number_of_instances  ; // keep track of number of instances of class B
    }

    void IncrementCounter()
    {
        counter  ;
    }

    int GetCounter() const
    {
        return counter;
    }

    int NumberOfInstances() const
    {
        return number_of_instances;
    }

private:
    int counter{ 0 };
    static int number_of_instances;
};

class A 
{
public:
    A(const std::shared_ptr<B>& b) :
        m_b{ b }
    {
    }
    
    // return a reference to the object shared_ptr m_b points to
    B& GetB() 
    {
        return *m_b;
    }

    // return a const reference to the object shared_ptr m_b points to
    const B& GetB() const
    {
        return *m_b;
    }

private:
    // https://en.cppreference.com/w/cpp/memory/shared_ptr
    std::shared_ptr<B> m_b;
};

int B::number_of_instances{ 0 };


int main()
{
    auto b = std::make_shared<B>();
    b->IncrementCounter();

    A a1(b);
    A a2(b);

    std::cout << "number of instances of B = " <<b->NumberOfInstances() << "\n";
    std::cout << "shared_ptr<B> reference count = " << b.use_count() << "\n";

    std::cout << a1.GetB().GetCounter();

    return 0;
}

CodePudding user response:

Note: I do not want to create copies of class B instance, I want A.getB().GetCounter() to always be the same as b.GetCounter().

Then you need to make A store a B& reference instead of a B object instance, eg:

class A {
public: 
    A(B& b);
    B& GetB();

private:
    B& b;
};
A::A(B& b) : b(b) {
}

B& A::GetB() {
    return b;
}

As long as the B object outlives the A object (which it does in your example), you will be fine, no (shared) pointers will be needed.

However, since you are declaring A before B, you can't use B at all in A as you have shown. The compiler won't know what B is while parsing A.

Since B doesn't depend on A for anything, you can simply swap the order of their declarations, eg:

class B {
public:
    B();
    void IncrementCounter();
    int GetCounter();

private:
   int counter = 0;
};

class A {
public: 
    A(B& b);
    B& GetB();

private:
    B& b;
};

Otherwise, if that is not an option for your situation, then you will have to use a forward declaration of B before declaring A, eg:

class B; // <--

class A {
public: 
    A(B& b);
    B& GetB();

private:
    B& b;
};

class B {
public:
    B();
    void IncrementCounter();
    int GetCounter();

private:
   int counter = 0;
};

Forward declaration only work when dealing with references and pointers, not with instances.

  • Related