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 wantA.getB().GetCounter()
to always be the same asb.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.