Assinging the Objects Which are Virtual Multiple Inherited - c++

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.

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.

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

c++ abstract class copy constructor call makes error

My question is very similar like other's, but a bit different. I have a sample code:
class B1 {
private :
int * ptr;
public:
B1() : a{ 1 } { ptr = new int{ 2 }; }
B1(const B1& other) : a{ other.a } { ptr = new int{ *other.ptr }; }
~B1() { delete ptr; }
int a;
virtual void smthing() = 0;
};
class D : B1 {
public:
D(int i) : B1{} {}
D(const D& a) : B1{ a } {}
void smthing() { return; };
};
int main() {
D d { 3 };
D dd { d };
return 0;
}
I am using vs2015, and this code is works, but gives me error: object of abstract class type "B1" is not allowed...
If I remove this line D(const D& a) : B1{ a } {}, the base class copy constructor is called and there's no problem, but if I need the derived class copy constructor how can I make this work without error?
Thanks for the answer!

When I get a case of `slicing`?

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;

How does the abstract base class avoid the partial assignment?

As is talked about in Item 33 in "More Effective C++", the assignment problem is
//Animal is a concrete class
Lizard:public Animal{};
Chicken:public Animal{};
Animal* pa=new Lizard('a');
Animal* pb=new Lizard('b');
*pa=*pb;//partial assignment
However, if I define Animal as an abstract base class, we can also compile and run the sentence:*pa=*pb. Partial assignment problem is still there.
See my example:
#include <iostream>
class Ab{ private: int a;
double b;
public:
virtual ~Ab()=0;
};
Ab::~Ab(){}
class C:public Ab{
private:
int a;
double b;
};
class D:public Ab{
private:
int a;
double b;
};
int main()
{
Ab *pc=new C();
Ab *pd=new D();
*pc=*pd;
return 0;
}
Do I miss something? Then what's the real meaning of the abstract base class?
I got the answer by myself. I missed a code snippet in the book.
Use protected operator= in the base class to avoid *pa=*pb. Use abstract base class to avoid animal1=animal2.Then the only allowed expressions are lizard1=lizard2;chicken1=chicken2;
See the code below:
#include <iostream>
class Ab{
private:
int a;
double b;
public:
virtual ~Ab()=0;
protected: //!!!!This is the point
Ab& operator=(const Ab&){...}
};
Ab::~Ab(){}
class C:public Ab{
public:
C& operator=(const C&){...}
private:
int a;
double b;
};
class D:public Ab{
public:
D& operator=(const D&){...}
private:
int a;
double b;
};
int main()
{
Ab *pc=new C();
Ab *pd=new D();
*pc=*pd;
return 0;
}
The abstract base class cannot help in case of assignment because the base sub-object is not instantiated (what an abstract class would block) but is sliced off the derived object (i.e. the assignment is done between already existing base sub-objects).
To avoid the problem the only solution I can think to is
make the assignment virtual
check in the assignment that the source instance is of the correct type
In code
#include <iostream>
struct Base {
int bx;
Base(int bx) : bx(bx) {}
virtual Base& operator=(const Base& other) {
bx = other.bx;
return *this;
}
};
struct A : Base {
int x;
A(int bx, int x) : Base(bx), x(x) {}
A& operator=(const Base& other) {
const A& other_a = dynamic_cast<const A&>(other);
Base::operator=(other);
x = other_a.x;
return *this;
}
};
struct B : Base {
int x;
B(int bx, int x) : Base(bx), x(x) {}
B& operator=(const Base& other) {
const B& other_b = dynamic_cast<const B&>(other);
Base::operator=(other);
x = other_b.x;
return *this;
}
};
The dynamic_cast<const A&>(other) is the operation that will fail if the object passed to the assignment operator is not of the correct derived type (it can be a sub-derived object, but this should be logically ok for an assignment source).
As an example:
int main(int argc, const char *argv[]) {
Base *pa1 = new A(1, 2);
Base *pa2 = new A(3, 4);
Base *pb1 = new B(5, 6);
Base *pb2 = new B(7, 8);
*pa1 = *pa2; std::cout << pa1->bx << "/" << dynamic_cast<A*>(pa1)->x << "\n";
*pb1 = *pb2; std::cout << pb1->bx << "/" << dynamic_cast<B*>(pb1)->x << "\n";
std::cout << "Ok so far\n";
*pa1 = *pb1; // Runtime error here (bad cast)
return 0;
}
It doesn't matter that your base class has pure virtual functions because you haven't defined the operator= for any of the classes. So when the compiler sees this statement:
*pc=*pd;
where pc and pd are both of type Ab, it will call the default assignment operator for Ab, which will result in partial assignment. As in the following example, I get the output as "Abstract Base" which is from abstract base class:
class A {
public:
virtual void foo() =0;
virtual A& operator=(const A& rhs) {
std::cout << "Abstract Base";
return *this;
}
};
class B : public A {
public:
virtual void foo() {
std::cout << "b:foo";
}
};
class C : public A {
public:
virtual void foo() {
std::cout << "c:foo";
}
};
int main()
{
A* b = new B();
A* c = new C();
*b = *c;
return 0;
}
Since you have not handled the assignment operators in your classes, you land up in situation partial assignment as Scot clearly describes in his article.
You need to handle assignments in your classes. In current design default implicit assignment operator of Ab is called and thus all the properties of children class are lost.
To avoid this you should have an implementation like this:
class Ab{ private: int a;
double b;
public:
virtual ~Ab()=0;
virtual Ab& operator=(const Ab& rhs){cout<<"in Ab="<<endl;}
};
Ab::~Ab(){}
class C:public Ab{
C& operator=(const Ab& rhs){cout<<"in C="<<endl;
return operator=(dynamic_cast<const C&>(rhs)); }
C& operator=(const C& rhs){
cout<<"do somethin in C="<<endl;
}
private:
int a;
double b;
};
class D:public Ab{
D& operator=(const Ab& rhs){cout<<"in D="<<endl;
return operator=(dynamic_cast<const D&>(rhs)); }
D& operator=(const D& rhs){
cout<<"do somethin in D="<<endl;
}
private:
int a;
double b;
};