Implicitly converting an object of one class to another - c++

I have the following working example, where I am passing an object of type Derived to a constructor that expects an object of type Bridge:
#include <iostream>
class Base {
public:
Base() {};
virtual Base* clone() const = 0;
virtual ~Base() {};
};
class Derived : public Base {
public:
Derived() {};
virtual Base* clone() const {
std::cout << "Cloned derived\n";
return new Derived(*this);
}
virtual ~Derived() {}
};
class Bridge {
public:
Bridge(const Base& b_) {
b = b_.clone();
std::cout << "Cloned b\n";
};
~Bridge() {}
private:
Base *b;
};
class Test {
public:
Test(const Bridge& b_) : b(b_) {};
private:
Bridge b;
};
int main()
{
Derived d;
Test t(d);
}
Why is this allowed? From what I can gather it works because of Bridge's constructor that takes a reference to a Base object. But I have a hard time figuring out what the order actually is.
Is the following timeline of what goes on correct?
The statement Test t(d); implies we have Bridge& b_(d) (as per Test's constructor)
Test's constructor creates a new object which is the one that b in Test is ultimately set to?

Almost.
Test expects Bridge and there is a Bridge constructor which accepts Base and Derived publically inherits from Base. So a temporary object of type Bridge is created using d and this is used to construct t.
But this happens in main not in the Test constructor. Further this temporary object is destroyed at the end of the Test t(d); statement. However by this point you have copied the temporary object in your Test constructor so everything seems to be OK (apart from the memory leaks).

Related

C++ Correct design to iterate over members of derived instances

I have a base class that holds a vector of pointers to derived classes and a virtual recursive method like this:
class Base
{
std::vector<Base*> vec;
public:
Base(std::vector<Base*> vec = {}) : vec {vec} {}
virtual ~Base() = default;
virtual void f() const
{
if (vec.size() == 0)
throw std::logic_error("Last children should implement f()")
for (auto * part : vec)
part->f();
}
}
The method f() is recursive and the last child of Base should override it. For example the following works
Where the first derived class is
class B : public Base
{
B() : Base() {}
virtual void f() const
{
std::cout << "In B\n";
}
}
class A : public Base
{
B b_,c_;
public:
A(B b, B c) : Base({&b_,&c_}), b_ {b}, c_{c} {}
}
If I call
B b,c;
A a(b,c);
a.f()
It will print twice "In B"correctly. Notice that A does not override f() so Base::f() is called, this loops and calls B::f() twice, once for b and once for c. However if I go one nested class more, for example by having
class C : public Base
{
A a_;
B b_;
public:
C(A a, B b): Base({&a_, &b_}), a_{a}, b_{b} {}
}
And I call C::f() the program segfaults. I suppose this is because there are some temporaries and their destructors delete the pointers held by Base. Is the solution to this to hold shared_ptr? or is there a better design? I cannot hold unique_ptr cause that would make all derived classes not copyable.
public C(A a, B b): Base({&a, &b}), a{a}, b{b} {}
Firstly, you can't have public there.
Your base points to the parameters of the constructor. Those parameters are destroyed when the constructor finishes and the pointers become invalid. Point to the members instead:
C(A a, B b): Base({&this->a, &this->b}), a{a}, b{b} {}
Note however that the implicit copy and move constructors and assignment operators of the class are broken because they will make the copied object point to the members of the copy source, rather than the members of the copy itself. So, you'll need implement those as well.
is there a better design?
Possibly a better approach: Instead of storing the pointers in the base sub object, write a virtual function that derived classes can override, and which returns a range of pointers to children.

usage of std optional mixed with shared_ptr

I have two derived classes as follows. This is the simplified design version that I have right now.
class A objects are copy-able but they are big. That is why I used reference in the constructor of the derived_1 class.
I used shared_ptr for the class derived_2 in order to make usage of p_a optional. I noticed that I can also use std::optional in the constructor of the class derived_2. By this I can give hint to the user that this argument is indeed optional.
Please take into consideration that this the simplified version and this member p_a is used in all three classes intensively. Also std::shared_ptr<A&> a is not the only argument for the constructor in the real example. I will be thankful if you show me how to use std::optional properly here.
Is it ok to mix std::optional with std::shared_ptr?
class A
{
int m_a;
public:
A(int a) :m_a(a) {};
};
class Base
{
protected:
std::shared_ptr<A> p_a; //Do I need to change type of p_a???
public:
Base() {};
void print()
{
if (p_a)
std::cout << "p_a is allocated\n";
}
void virtual check() = 0;
};
class derived_1 : public Base
{
public:
derived_1(const A& a)
{
p_a = std::make_shared<A>(a);
}
void check() {};
};
class derived_2 : public Base
{
public:
derived_2(std::shared_ptr<A&> a) //can I use std::optional instead??
{
if (a)
p_a = a;
}
void check() {};
};

copy constructor is implicitly deleted because the default definition would be ill-formed

I've got a class A (from a library over which I have no control) with a private copy constructor and a clone method, and a class B derived from A. I would like to implement clone for B as well.
The naive approach
#include <memory>
class A { // I have no control here
public:
A(int a) {};
std::shared_ptr<A>
clone() const
{
return std::shared_ptr<A>(new A(*this));
}
private:
A(const A & a) {};
};
class B: public A {
public:
B(int data, int extraData):
A(data),
extraData_(extraData)
{
}
std::shared_ptr<B>
clone() const
{
return std::shared_ptr<B>(new B(*this));
}
private:
int extraData_;
};
int main() {
A a(1);
}
however, fails, since the copy constructor of A is private:
main.cpp: In member function ‘std::shared_ptr<B> B::clone() const’:
main.cpp:27:42: error: use of deleted function ‘B::B(const B&)’
return std::shared_ptr<B>(new B(*this));
^
main.cpp:17:7: note: ‘B::B(const B&)’ is implicitly deleted because the default definition would be ill-formed:
class B: public A {
^
main.cpp:14:5: error: ‘A::A(const A&)’ is private
A(const A & a) {};
^
main.cpp:17:7: error: within this context
class B: public A {
There might a way to make use of A::clone() for B::clone(), but I'm not sure how this would work exactly. Any hints?
I presume it's a typo that your B has no public members at all,
and that you're missing a public: before the definition of B::B(int,int).
The author of the class represented by your A apparently wants it to be
cloneable but not copy constructible. That would suggest he or she wants all
instances to live on the heap. But contrariwise, there's the public
constructor A::A(int). Are you sure you are right about that?
It's plausible to suppose that the class can reveal enough information
about a given instance to constitute another instance. E.g., putting
a little more flesh on A:
class A {
public:
A(int a)
: data_(a){};
std::shared_ptr<A>
clone() const
{
return std::shared_ptr<A>(new A(*this));
}
int data() const {
return data_;
}
private:
A(const A & a) {};
int data_;
};
And if that is true, then the public constructor would render it merely
inconvenient to circumvent the private, undefined copy constructor:
A a0(1);
A a1{a0.data()}; // Inconvenient copy construction
So I'm less than confident that A faithfully represents the problem
class. Taking it at face value, however, the question you need to answer
is: Can you even inconveniently copy construct an A?
If not then you're stuck. If so, then you can use inconvenient copy
construction of A to expressly define a conventional copy constructor for B,
which is all you need. E.g.
class B: public A {
public:
B(B const & other)
: A(other.data()),extraData_(other.extraData_){}
B(int data, int extraData):
A(data),
extraData_(extraData)
{
}
std::shared_ptr<B>
clone() const
{
return std::shared_ptr<B>(new B(*this));
}
int extradata() const {
return extraData_;
}
private:
int extraData_;
};
#include <iostream>
int main()
{
B b(1,2);
std::shared_ptr<B> pb = b.clone();
std::cout << pb->data() << std::endl;
std::cout << pb->extradata() << std::endl;
return 0;
}
You need to make the copy-constructor of A protected so that the derived class could use it:
protected:
A(const A & a) { /*...*/ }
Hope that helps.
The reason the default definition of B's copy constructor is ill-formed is because - if it was permitted - it would invoke the private (therefore inaccessible to B) and not defined copy constructor of A.
Make A's copy constructor either protected or public, so it is accessible to B. Another (really bad) option is to declare class B as a friend of A. All possibilities would also require you to provide a definition for A's copy constructor.

Reference variable and virtual functions

I've found a strange behavior while using a reference variable.
Here is class implementations:
class Base {
public:
virtual void Method() = 0;
};
class DerivedA : public Base {
public:
virtual void Method() {}
}
class DerivedB : public Base {
public:
virtual void Method() {}
}
Here is an example code which have the strange behavior:
void main(int argc, char *argv[]) {
DerivedA a;
DerivedB b;
Base &base = a;
base.Method(); // Calls DerivedA::Method
base = b;
base.Method(); // Calls DerivedA::Method!!! Why doesn't call DerivedB.Method()?
}
In conclusion, it seems that the virtual function pointer table "associated" to the reference variable is determine only when initializing the reference variable. If I re-assign the reference variable the vfpt doesn't change.
What happens here?
Base &base is a reference, i.e. alias to the a object, so the assignment base = b is equivalent to a = b, which leaves the base thingie still the same object of the same class. It is not a reassignment of pointer as you seem to assume.
References can only be initialized once. You can not assign a new object to a reference. What is actually happening here is that operator= of Base is called and the underlying object is still DerivedA and not DerivedB.

Creating clone of an object not working with virtual base class

#include<iostream>
using namespace std;
class Something
{
public:
int j;
Something():j(20) {cout<<"Something initialized. j="<<j<<endl;}
};
class Base
{
private:
Base(const Base&) {}
public:
Base() {}
virtual Base *clone() { return new Base(*this); }
virtual void ID() { cout<<"BASE"<<endl; }
};
class Derived : public Base
{
private:
int id;
Something *s;
Derived(const Derived&) {}
public:
Derived():id(10) {cout<<"Called constructor and allocated id"<<endl;s=new Something();}
~Derived() {delete s;}
virtual Base *clone() { return new Derived(*this); }
virtual void ID() { cout<<"DERIVED id="<<id<<endl; }
void assignID(int i) {id=i;}
};
int main()
{
Base* b=new Derived();
b->ID();
Base* c=b->clone();
c->ID();
}//main
On running:
Called constructor and allocated id
Something initialized. j=20
DERIVED id=10
DERIVED id=0
My question is related to this, this and this post.
In the first link, Space_C0wb0y says
"Since the clone-method is a method of
the actual class of the object, it can
also create a deep-copy. It can access
all members of the class it belongs
to, so no problems there."
I don't understand how a deep copy can happen. In the program above, not even a shallow copy is happening. I need it to work even if the Base class is an abstract class. How can I do a deep copy here? Help please?
Well, your copy constructor does nothing, so your clone method does nothing in the way of copying.
See line Derived(const Derived&) {}
EDIT: if you add code to copy by assignment all members of Derived, it will become a shallow copy. If you also copy (by making a new instance) your instance of Something, it will become a deep copy.