Constructor initialization order and reference passing - c++

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

Related

How to inherit specific variables from different classes inherited from one base class?

I have a Base class A, 2 childs B and C that both inherits from A, and I have a class D that inherits from both B and C in which I want to take _a from B and _b from C without having to do a virtual method for print_a and print_b if possible
# include <iostream>
class A
{
public:
A(void) : { }
~A(void) { }
inline void print_a(void) { std::cout << _a << std::endl; }
inline void print_b(void) { std::cout << _b << std::endl; }
protected:
int _a;
int _b;
};
class B : virtual A
{
public:
B(int a) : A() { _a = a, _b = 0; }
~B(void) { }
protected:
using A::_a;
using A::_b;
};
class C : virtual A
{
public:
C(int b) : A() { _a = 0, _b = b; }
~C(void) { }
protected:
using A::_a;
using A::_b;
};
class D : virtual public A, private B, private C
{
public:
D(void) : A(), B(5), C(5) { }
~D(void) { }
private:
using B::_a;
using C::_b;
};
int main(void)
{
D foo;
foo.print_a();
foo.print_b();
return (0);
}
My D class is inheriting methods print_a and print_b from A and I want it to inherit _a = 5 from B and _b = 5 from C, but it doesn't work, it outputs:
0
5
Instead of:
5
5
As you are using virtual for all base classes you end up with D having only one A (and not one as base of D, one as base of B and one as base of C).
The problem is with your constructors.
The constructor of a derived class calls the constructors of all base classes in the order they are given in the base class list, so in your case D::D calls:
A::A() -> _a and _b uninitialized
B::B(5)
_a = 5
_b = 0
C::C(5)
_a = 0
_b = 5
It is unclear why you are setting _a and _b multiple times in different constructors. It would be better to initialize members in the constructor's member initializer list and not assign it in a constructor body. You could for example write
A(int a, int b) : _a(a), _b(b) {}
B(int a) : A(a, 0) {}
C(int b) : A(0, b) {}
D() : A(5, 5), B(5), C(5) {}
Here D::D() would result in
A(5, 5) -> _a initialized to 5, _b initialized to 5
B(5) -> no effect (on A/_a/_b)
C(5) -> no effect (on A/_a/_b)
If you want to stick with your design and initialize the variables in the constructor bodies, you can simply add code to D::D to overwrite whatever the base class constructors set:
D() : A(), B(5), C(5) { _a=5; _b=5; }

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());

dynamic_cast fails when cast a derived class to base class

In Primer c++ 5th
class A {
public:
A() : a(1) {}
virtual ~A() = default;
private:
int a;
};
class B : public A {
public:
B() : b(2) {}
private:
int b;
};
class C : public B {
public:
C() : c(3) {}
private:
int c;
};
//class D : public B, public A { cause error
// public:
// D() : d(4) {}
// private:
// int d;
//};
int main()
{
//A *pa = new C;
//B *pb = dynamic_cast<B*>(pa); //1st case
B *pb = new B;
C *pc = dynamic_cast<C*>(pb); //2nd case
cout << pc << endl;
//A *pa = new D;
//B *pb = dynamic_cast<B*>(pa); //3rd case
}
//output: 0 cast failure
Q1:
Here in the above code .I can understand why the 2nd case doesn't work, but
the type of pb-pointed object is B which is the public base class of C .And this is the 2nd situation of what's said in Primer c++.
So why the 2nd case doesn't work while primer c++ said this kind of cast will succeed?
Q2:
the 3rd case. Errors occurred during compilation
error: ā€˜Aā€™ is an ambiguous base of ā€˜Dā€™
What does this error mean?
in your second example you create a class B, B is a base class for C.
so you can't cast a base class to some derived class.
this will work:
B *pb = new C();
C *pc = dynamic_cast<C*>(pb);
regarding 3rd example D derive from B and A, but B also derive from A, this make problems for compiler. you try to derive 2 times for A, the compiler will not know what function A to use, the base A or the derived version of B.
al
you should read more about base and derived classes.

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();
}

Code Refactoring Trying to use Polymorphism and std::map

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.