Code Refactoring Trying to use Polymorphism and std::map - c++

I have this class
struct B {
B( int x=0 ) { }
virtual void something() {
std::cout << "B()";
}
};
struct A {
B b;
int a;
A( int a, int b_ ) : a(a), b(b_) {a}
};
I have implemented another class C
struct C : public B {
C( int x ) : B(b) { }
virtual void something() {
std::cout << "C()";
}
};
What is the best way to get A use C instead of B ?
I already tried this :
struct A {
B & b;
int a;
A( int a, B &b_ ) : a(a), b(b_) {a}
};
But then I have to use std::map<int, A>
which is giving compilation errors:
'A::A' : no appropriate default constructor available.
so i did this :
struct A {
B & b;
int a;
A( int a=0, B &b_=B() ) : a(a), b(b_) {a}
};
in my main
std::map<int,A> mmap;
for( int i=0;i<5;++i ) {
auto & b = C();
mmap.insert( std::make_pair(i,A(i,b) ) ) ;
}
but these C's object in mmap's A become B as soon as auto & b goes out of scope.
Its not working. How to fix it ?

In the A constructor, you try to assign a temporary instance of B to reference to B, which is illegal.
What you have to do is to change this reference by a pointer to this class :
#include <iostream>
#include <memory>
#include <map>
using namespace std;
struct B {
B( int x=0 ) { }
virtual void something()
{
std::cout << "B()";
}
};
struct A {
shared_ptr<B> b;
int a;
A( int a = 0, shared_ptr<B> b = shared_ptr<B>(new B()) ) : a(a), b(b) {}
};
struct C : public B {
C( int x ) { }
virtual void something()
{
std::cout << "C()";
}
};
int main()
{
shared_ptr<B> b = shared_ptr<B>( new C(0));
// Polymorphic test
b->something();
A a (0, b);
// map test
map<int, A> my_map;
my_map[0] = a;
return 0;
};
If you can not use C++11, just change smart pointers by naked pointers and handle the dynamic memory properly as usual. Or even better : use the Boost library, as mentioned by chris.

Related

How to save an object inside another object in C++

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?
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;
}
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.

Serialising/Deserialising multiple inherited Trivially Copiable C++ structs

Consider the following piece of code:
struct A {
int a;
A(int a): a(a) {}
char *get_data() { return reinterpret_cast<char*>(this); }
};
struct B: public A {
int b[100];
B() : A(0) {}
};
Is it safe to do the following?
B b;
Write(/* key= */ 1, b.get_data());
A *a = reinterpret_cast<A *>(Read(1));
// Some code here.
B *b = reinterpret_cast<B *>(a->get_data());

Issue in accessing member variables

#include<iostream>
class A {
int a, b;
public:
void setdata(int x, int y) { a = x; b = y; }
void showdata() { std::cout << a << b; }
};
class B : public A { };
int main() {
A a1;
B b1;
a1.setdata(5, 4);
a1.showdata();
b1.showdata();
}
I just want to print the values of the a and b members using the b1 object of class B, as it can access the member functions of class A since class B has public inheritance of class A. But, I am getting garbage values when I try to print the values of a and b using b1.
Can someone explain why this is happening and how to fix it?
a1 and b1 are completely separate object instances in memory. They have their own copies of the a and b members in memory. They have nothing to do with each other at all. Whatever you do to a1 does not affect b1 at all, and vice versa.
You are initializing the members of a1 only, you are not initializing the members of b1 at all. That is why you are seeing garbage when you try to print out the members of b1.
Before calling b1.showdata(), you need to call b1.setdata() to initialize b1's members, eg:
int main() {
A a1;
B b1;
a1.setdata(5, 4);
a1.showdata();
b1.setdata(1, 2); // <-- add this!
b1.showdata();
}
You should also give class A a default constructor that initializes the members to default values, in case setdata() is not called after construction (such as what happened in your case), eg:
class A {
int a, b;
public:
A() : a(0), b(0) {} // <-- add this!
void setdata(int x, int y) { a = x; b = y; }
void showdata() { std::cout << a << b; }
};
Alternatively, you might consider giving class A and class B a constructor that takes values as input, eg:
class A {
int a, b;
public:
A() : a(0), b(0) {}
A(int x, int y) : a(x), b(y) {} // <-- add this!
void setdata(int x, int y) { a = x; b = y; }
void showdata() { std::cout << a << b; }
};
class B : public A {
public:
B() : A() {}
B(int x, int y) : A(x, y) {}
};
/* or simpler:
class B : public A {
public:
using A::A; // <-- inherit all constructors
};
*/
int main() {
A a1(5, 4);
B b1(1, 2);
a1.showdata();
b1.showdata();
}

brace-or-equal initialization vs constructor delegation

Perhaps my title might translate to "apples vs oranges", but I'm not quite sure so I'd like the SO community's help understanding some best practices.
Suppose I have the two examples.
brace-or-equal initialization
class foo
{
public:
foo() {}
foo(int a) : m_a(a) {}
foo(int a, int b) : m_a(a), m_b(b) {}
foo(int a, int b, int c) : m_a(a), m_b(b), m_c(c) {}
private:
int m_a = 1;
int m_b = 2;
int m_c = 3;
};
constructor delegation
class foo
{
public:
foo() : m_a(1), m_b(2), m_c(3) {}
foo(int a) : foo() { m_a = a; }
foo(int a, int b) : foo() { m_a = a; m_b = b; }
foo(int a, int b, int c) : foo() { m_a = a; m_b = b; m_c = c; }
private:
int m_a;
int m_b;
int m_c;
};
I feel like the first is better because it results in no double-initialization of variables. In the 2nd example, the last overload of foo's constructor is the worst because each member variable is initialized twice.
Which is the preferred method here? And assuming the former is preferred, when are delegated constructors useful?
You want to delegate from the constructor that takes fewer arguments to the constructor that takes the most, giving default values for the extra parameters:
foo( int a, int b, int c ) : m_a(a), m_b(b), m_c(c) {}
foo( int a, int b ) : foo( a, b, 3 ) {}
foo( int a ) : foo( a, 2, 3 ) {}
foo() : foo( 1, 2, 3 ) {}
Like clcto pointed out, you should do delegation differently.
In reality we can do a little better (With your given example!!!) using default param values:
class foo
{
public:
// no longer need all your other constructors
foo(int a=1, int b=2, int c=3) : m_a(a),m_b(b),m_c(c){}
private:
int m_a;
int m_b;
int m_c;
};
Your actual code may be different; i.e. you want to sometimes initialize b and not a or c, so you could instead use one of the other answers posted.

Constructor initialization order and reference passing

Hi I have a question about the constructor initialization order. Given below
struct B {}
struct A
{
B& b;
A(B& b) : b(b) {}
}
struct C
{
B b;
A a;
C() : b(),a(b) {}
}
struct D
{
A a;
B b;
D() : a(b),b() {}
}
I know that C is valid as b gets initialized before a. But what about D? b wouldn't have been constructed yet, but the address should already be known, so it should be safe?
Thanks
They're both valid because A doesn't call into B at all. If A accessed a data member or member function of B, then that would be invalid. In the existing case of A, it's impossible to produce an invalid example.
just a sample to show you when stuff happens
struct B {
B() {
print("struct B / constructor B", 1);
}
};
struct A
{
B& b;
A(B& b) : b(b) {
print("struct A / constructor with B", 1);
};
};
struct C
{
B b;
A a;
C() : b(),a(b) {
print("struct C / constructor C", 1);
};
void dummy()
{
print("dummy",1);
}
};
struct D
{
A a;
B b;
D() : a(b),b() {
print("struct D / constructor D", 1);
};
void dummy()
{
print("dummy",1);
}
};
int main(int argc, char* argv[])
{
D dTest;
dTest.dummy();
C cTest;
cTest.dummy();
}
--- output
struct A / constructor with B
struct B / constructor B
struct D / constructor D
dummy
struct B / constructor B
struct A / constructor with B
struct C / constructor C
dummy