When I get a case of `slicing`? - c++

Let's look the next code (for example):
class A {
int n;
public:
int f() const { return n; }
void set(int i) { n = i; }
};
class B : public A {
public:
int g() const { return f()+1; }
};
void h(const A& a) {
a.f();
}
int main() {
B b;
A& a = b;
A* ptrA = new B;
h(b);
delete ptrA;
return 0;
}
Now, Let's look about these lines code:
A& a = b; // Is there "slicing"? (why?)
A* ptrA = new B; // Is there "slicing"? (why?)
A a = b; // Is there "slicing"? (why?)
I do not really understand when I want to use any of them, and when, alternatively, you will not be allowed to use one of them. What is really the difference between these lines..

Slicing is when you assign a derived object to a base instance. For example:
B b;
A a = b;
The issue here is that the copy constructor for A that is being called only sees the A part of B, and so will only copy that. This is an issue if your derived class has added additional data or overridden the behaviour of A.
When you assign an object to a reference or a pointer there is no slicing. So
A &a = b;
Is fine, as is:
A *a = &b;

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.

Deallocating the pointer but not its values

I have this type of code:
class A
{
private:
int z;
std::vector<B*> v;
public:
A();
A(int z, std::vector<B*> v);
~A();
// ...
void setV(std::vector<B*> v);
}
class B
{
// Some attributes
B();
}
int main()
{
A* a = new A();
B* b = new B();
b->setSomething(s);
std::vector<B*> vec = {};
vec.push_back(b);
a->setV(vec);
// ...
delete b;
// ...
delete a;
}
The problem is that I want to delete b before a. But I will delete the values pointed by b, that will be a problem for a.
If I just delete a, and not b, all the values are correctly deleted by this destructor:
A::~A()
{
for (B* b : this.v)
{
delete b;
}
}
But valgrind says I have a 24B memory leak if I just delete a. Because I still have the b pointer not deallocated.
How can I delete b, before a, without losing the values pointed by b ?
Thank you

Segmentation fault when using Used-defined conversion operator

I have implemented the following piece of code
#include <iostream>
#include <memory>
class A
{
public:
int a;
virtual ~A()
{
}
};
class B : public A
{
public:
int b;
virtual ~B()
{
}
};
class E : public B
{
public:
~E()
{
}
};
class D
{
public:
operator std::shared_ptr<A>()
{
std::shared_ptr<A> pa = std::make_shared<A>();
pa->a = this->y;
return pa;
}
operator std::shared_ptr<B>()
{
std::shared_ptr<A> pb = std::make_shared<B>();
pb = *this;
(std::static_pointer_cast<B>(pb))->b = this->x;
return std::static_pointer_cast<B>(pb);
}
virtual ~D()
{
}
int x;
int y;
};
int main()
{
D d;
d.x = 6;
d.y = 7;
std::shared_ptr<E> pE = std::make_shared<E>();
std::shared_ptr<A> pa = pE;
std::shared_ptr<B> pB = std::dynamic_pointer_cast<B>(pa);
pB = d;
std::cout << "a " << pB->a << "b " << pB->b << std::endl;
return 0;
}
What I try to do is to convert the instance of class D, d, in a instance of shared pointer B which is derived from class A.
The B inherits the class A, and E inherits the class B.
When the program terminates, the program crashes in the destructor of class A.
I used GDB and see that this is NULL.
Does anyone have an idea why this happens?
Inside of D::operator std::shared_ptr<B>(), the use of std::static_pointer_cast<B>(pb) is undefined behavior, because pb does not point at an instance of B at that point, so it is illegal to cast the A pointer to a B pointer and access B's members. pb is pointing at the instance of A created by std::make_shared<A>() in D::operator std::shared_ptr<A>(). On the statement pb = *this;, you are discarding the B object you created and taking ownership of the A object that *this returns.
Thus, inside of main(), pB ends up pointing at an invalid B object and tries to destruct that object when main() exits, which is why you end up crashing the A destructor.
Had you used dynamic_pointer_cast instead of static_pointer_cast inside of D::operator std::shared_ptr<B>(), you would have ended up with a NULL pointer and likely crashed inside of D::operator std::shared_ptr<B>() when accessing B::b, instead of crashing in main().
You need to fix your operator std::shared_ptr<B>() to operate on a valid instance of B, not on an instance of A. For example:
operator std::shared_ptr<B>()
{
std::shared_ptr<B> pb = std::make_shared<B>();
std::shared_ptr<A> pa = *this;
*static_pointer_cast<A>(pb) = *pa; // <-- copy pa->a to pb->a ...
// or: simply do this instead:
// pb->a = pa->a;
pb->b = this->x;
return pb;
}

Assinging the Objects Which are Virtual Multiple Inherited

I have a problem with assigning the same objects with multiple inheritance which also have diamond problem. Here is the skeleton code of my project.
H.h
class H
{
protected:
int a;
int b;
int c;
public:
H();
H(int a);
//Setter and getters
};
Y.h
class Y : virtual H
{
public:
Y();
Y(int a);
};
D.h
class D : virtual H
{
public:
D();
D(int a);
};
An.h
class An : Y , D
{
public:
An();
An(int a);
};
I would like to assign one An object to another. But i get this error: error C2582: 'operator =' function is unavailable in 'An'
I searched google but found nothing. I am working on Visual Studio 2010
It works on Y or D or H like :
int main()
{
Y *a = new Y[4];
Y *b = new Y[4];
a[0] = b[0];//this is not the problem
}
Main.cpp
int main()
{
An *a = new An[4];
An *b = new An[4];
a[0] = b[0];//this is the problem
}
How can i solve this problem.
Thanks in advance.
Do you mean this?
An *a = new An(3);
An *b = new An(4);
a = b;//this is not a problem
In your program,
AN *a = An(3); // not possible
is not psssible as lhs is An * and rhs is An
The following is also fine:
An a = An(3);
An b = An(4);
a = b;
I found the solution. The code should be like this :
class A {
private:
A& operator=(const A& a){}
};
class B : public A {
public:
// try the following line to resolve the error
// void operator=(const B& b){}
};
int main() {
B b1;
B b2;
b1 = b2; // C2582
}
When you define the
void operator=(const B& b){}
into the An class as public. The problem solved.

is this possible in C++?

to create an instance of another class from a class even if the class I want to have an instance of is declared next of the class I am creating an instance from. Just like in C# and Java.
Thank you
You can use a forward declaration for some purposes, but you will need to have the complete type whenever you actually make use of it. It could be advisable to make the question more specific as to what you really want to achieve, as there might be simpler approaches to your problem (if order is important it might indicate a circular dependency between classes A and B, and that is not usually good).
class B;
class A
{
public:
A( B b, B* bp, B& br ) : bp_(bp), br_(br) {} // ok, incomplete types can be used as argument types
B f()
// { return B(); } // nok: cannot create objects of incomplete type
;
B* f2() { return bp_; } // ok
B& f3() { return br_; }; // ok
void g()
// { bp_->g(); br_.g(); } // nok: cannot call methods of an incomplete type
;
void g( B const & b )
// { b.g(); } // nok: cannot call methods of an incomplete type
private:
B * bp_; // ok (also const version)
B & br_; // ok (also const version)
// B b_; // nok: B must be a complete type here
};
class B { // A is complete, any use is correct here
void g() {}
};
// From here on, B is a complete type and can be used in any possible way
B A::f() {
return B(); // ok, now B is complete
}
void A::g() {
br_.g(); // ok, B is complete here
bp_->g(); // ok, B is complete here
}
void A::g( B const & b ) {
b.g();
}
Sure. You just need a forward declaration. Something like this works just fine:
#include <iostream>
class B;
class A {
public:
void hello( B &b );
void meow();
};
class B {
public:
void hello( A &a );
void woof();
};
void A::hello( B &b ) { b.woof(); }
void A::meow() { std::cout << "Meow!" << std::endl; }
void B::hello( A &a ) { a.meow(); }
void B::woof() { std::cout << "Woof!" << std::endl; }
int main() { A a; B b; a.hello( b ); b.hello( a ); return 0; }
The key here is that you can only use pointers or references to a class until it has been fully defined. So in the example I gave, the hello() method in A can be declared to take a reference to B, even though we haven't defined B at the point. After the definition of B, however, the definition of the method A::hello() is free to use B as it pleases.
I guess you mean to do something like this:
class B; //Forward declaration
class A
{
private:
B b;
};
class B
{
};
This is not possible in C++ as the compiler needs to know the sizeof(B) when compiling class A.
As a solution what you can do is:
class B; //Forward declaration
class A
{
public:
A();
~A();
private:
B* m_pB; //Store a pointer to B
};
class B
{
};
A::A()
{
m_pB = new B; //Create an instance of B
}
A::~A()
{
delete m_pB; //Explictly deallocate the memory.
m_pB = NULL;
}
Once you forward declare B in the header you can use it in the .cpp file without trouble to access public variables and methods.