Swap-Idiom of abstract class with private data members - c++

Assume we have this two classes, with implemented swap-idioms. The copy constructor and assignment operator of the base class are deleted, as it makes no sense. However the swap-method is implemented, as it holds a member.
namespace std
{
template<>
void swap<Base>(Base& a, Base& b)
{
a.swap(b);
}
template<>
void swap<Derived>(Derived& a, Derived& b)
{
a.swap(b);
}
}
class Base
{
public:
Base(int ID) : ID_(ID) {}
virtual std::string getString()=0;
Base(const Base&)=delete;
operator=(const Base&)=delete;
void swap(Base& rhs)
{
std:swap(ID_, rhs.ID_);
}
private:
int ID_;
}
class Derived : public Base
{
public:
Derived(int ID, bool Value) : Base(ID), Value_(Value) {}
virtual ~Derived() {}
Derived(Derived& rhs)
{
std::swap(*this, rhs);
}
virtual std::string getString() {return Value_ ? "True" : "False"}
void swap(Derived& lhs, Derived& rhs)
{
std::swap(static_cast<Base&>(lhs), static_cast<Base&>(rhs);
std::swap(lhs.Value_, rhs.Value_);
}
private:
bool Value_;
}
As seen in many examples, this would be the standard way to do it I suppose.
However, I see a problem with the public Base::swap, as it should not be possible to swap only the abstract base-class!
Wouldn't it be better to remove the template for the Base class and make the Base::swap Method protected:
class Base
{
...
protected:
void swap(Base& rhs, Base &lhs);
}
class Derived : public Base
{
...
public:
void swap(Derived& lhs, Derived& rhs)
{
Base::swap(static_cast<Base&>(lhs), static_cast<Base&>(rhs);
std::swap(lhs.Value_, rhs.Value_);
}
}
Assuming, there is another class derived from base, with the first implementation it would be possible to swap the ID, however the data members of the derived objects would stay the same.
So, am I right thinking that swapping of a abstract class should not be possible from outside?

The copy constructor and assignment operator of the base class are deleted, as it makes no sense.
Actually, this is terrible. Now you made Derived uncopyable! Why? There is no reason to add this restriction. The default copy constructor and assignment operator of Base are perfectly reasonable in the context of copying the most-base class of the hierarchy.
Once you undo that, there's no need to do anything else as std::swap(derived1, derived2) would already do the right thing. The default move construction/operation is correct. It's always good to let the compiler do things for you.
But if you want to override swap anyway, the correct way to do that would be as a non-member friend:
class Base {
...
friend void swap(Base& lhs, Base& rhs) {
using std::swap;
swap(lhs.ID_, rhs.ID_);
}
};
class Derived : public Base {
...
friend void swap(Derived& lhs, Derived& rhs) {
using std::swap;
swap(static_cast<Base&>(lhs), static_cast<Base&>(rhs));
swap(lhs.Value_, rhs.Value_);
}
};
Also, your Derived copy constructor makes no sense. Remove it as per the first paragraph of my answer.

Related

Virtual comparison operator

Is there any reason to make the op== in a C++ base class non-virtual, i.e., is there any downside to this implementation:
class A {
public:
virtual bool operator== (const A& rhs) { ... }
};
class B : public A {
public:
bool operator== (const A& rhs) override { /* cast rhs to const B& */ {}
};
In my book they recommend to make the op== non-virtual and let it call a protected virtual member function which performs the polymorphism instead. It doesn't say anything about why they don't use the op== directly like I do in my example above. Is there a good reason I'm overlooking?

returning derived class from overrided method, declared as returning base copy

This is a recurrent problem once again. Someone know a easy way to do that? Imagine I have the following:
class Base
{
public:
...
Base property(const std::string& name)=0;
};
class Derived:public Base
{
public:
Derived();
Derived(const Derived&& val);
Base property(const std::string& name)
{
Derived z;
return z;
}
}
There is a way for the Derived::property return being (internally) a Derived copy instead of only Base part copy, and with the Derived move constructor invoked?
May be a stupid question, but really I dont find solution. Why copy constructors on return dont copy the specialized class?
Thanks you!
You can't do this.
Returning by value conceptually (ignoring RVO and move semantics) means making a copy of whatever you return by using the copy constructor of the type which the function is declared to return. If you return a Derived, a copy of type Base will be made and you'll lose the Derived part of the object. This is known as slicing.
If you want to return a Derived object as a Base, you'll need to use pointers.
The only aproximation I can find for who search something similar (related with X3liF, TartanLlama and other responses)
#define overridable(T) ovr<T>
#define return_overload_allowed(TYPE) friend struct ovr<TYPE>; virtual void* clone() const
#define return_overload_basic_allowed(TYPE) friend struct ovr<TYPE>; virtual void* clone() const{return new TYPE(*this);}
template<typename T> struct ovr
{
T* _obj;
ovr(const T& t)
: _obj(reinterpret_cast<T*>(t.clone()))
{;}
ovr(ovr<T>&& v)
: _obj(v._obj)
{
v._obj=nullptr;
}
operator T&()
{
return *_obj;
}
virtual ~ovr()
{
delete _obj;
}
};
class BASE
{
return_overload_basic_allowed(BASE);
public:
virtual overridable(BASE) method1();
virtual ~BASE();
};
class DERIVED: public BASE
{
return_overload_basic_allowed(DERIVED);
public:
virtual overridable(BASE) method1()
{
DERIVED a;
return a;
}
virtual ~DERIVED();
};
DERIVED a;
auto x = a.method1();
BASE& really_derived = x;
This compiles fine. But don't meet practical and smart requiriments... :(

copy & swap in base and derived class

I recently read about copy & swap and am now trying to implement the ctors in a base and derived class. I have the four constructors in both my base and derived class, however I am unsure how to implement the assignment operator of the derived class.
explicit Base(int i) : m_i{i} {}
Base(const Base & other) : m_i{other.m_i}
Base(Base && other) : Base(0) { swap(*this, other); }
Base & operator=(Base other) { swap(*this, other); return *this; }
friend void swap(Base & a, Base & b) noexcept {
using std::swap;
swap(a.m_i, b.m_i);
}
explicit Derived(int j) : Base(42), m_j(j) {}
Derived(const Derived & other) : Derived(other.m_j) {}
Derived(Derived && other) : Derived(other.m_j) { swap(*this, other); }
Derived & operator=(Derived other) { /*???*/ }
friend void swap(Derived & a, Derived & b) noexcept {
using std::swap;
swap(a.m_j, b.m_j);
}
Consider using = default as much as possible. And if we are talking about public inheritance, you really need a virtual destructor as well.
Here is how your Base would look using the copy/swap style:
class Base
{
int m_i;
public:
virtual ~Base() = default;
Base(const Base& other) = default;
Base& operator=(Base other) noexcept
{
swap(*this, other);
return *this;
}
Base(Base&& other) noexcept
: Base(0)
{
swap(*this, other);
}
explicit Base(int i) noexcept
: m_i{i}
{}
friend void swap(Base& a, Base& b) noexcept
{
using std::swap;
swap(a.m_i, b.m_i);
}
};
The only difference from what you have is that I've added the virtual destructor, and used = default for the copy constructor.
Now for Derived:
class Derived
: public Base
{
int m_j;
public:
Derived(const Derived& other) = default;
Derived& operator=(Derived other) noexcept
{
swap(*this, other);
return *this;
}
Derived(Derived&& other) noexcept
: Derived(0)
{
swap(*this, other);
}
explicit Derived(int j) noexcept
: Base(42)
, m_j{j}
{}
friend void swap(Derived& a, Derived& b) noexcept
{
using std::swap;
swap(static_cast<Base&>(a), static_cast<Base&>(b));
swap(a.m_j, b.m_j);
}
};
I've let the compiler implicitly take care of the destructor since the compiler will implicitly give me a virtual one that does the right thing in this case.
Again I've explicitly defaulted the copy constructor. This corrects a bug in your version which neglects to copy Base.
The operator= looks just like the Base version.
The Derived move constructor does not need to move or copy anything from other since it is going to swap with other.
The Derived swap function must swap the Base part as well as the Derived part.
Now consider not using the copy/swap idiom. This can be surprisingly easier, and in some cases, higher performing.
For Base you can use = default for all 5 of your special members:
class Base
{
int m_i;
public:
virtual ~Base() = default;
Base(const Base&) = default;
Base& operator=(const Base&) = default;
Base(Base&&) = default;
Base& operator=(Base&&) = default;
explicit Base(int i) noexcept
: m_i{i}
{}
friend void swap(Base& a, Base& b) noexcept
{
using std::swap;
swap(a.m_i, b.m_i);
}
};
The only work that is really required here is your custom constructor and swap function.
Derived is even easier:
class Derived
: public Base
{
int m_j;
public:
explicit Derived(int j) noexcept
: Base(42)
, m_j{j}
{}
friend void swap(Derived& a, Derived& b) noexcept
{
using std::swap;
swap(static_cast<Base&>(a), static_cast<Base&>(b));
swap(a.m_j, b.m_j);
}
};
All 5 of the special members can be implicitly defaulted!
We couldn't default them in the Base because we needed to specify the virtual destructor, which inhibits the generation of the move members, and the generation of the copy members is deprecated with a user-declared destructor. But since we do not need to declare the destructor in Derived, we can just let the compiler handle everything.
As one of the big selling points of copy/swap is reduced coding, it can be ironic that using it can actually require more coding than letting the compiler default the special members.
Of course if the defaults do not do the right thing, then don't use them. I'm simply saying that the defaults should be your first choice, ahead of copy/swap.
You implement op= exactly the same way for Derived as for Base:
Derived& operator=(Derived other) { swap(*this, other); return *this; }
I hope you are aware of the up- and down-sides of passing the argument by value there, though:
Up-side: Only one function needed for all value categories.
Down-Side: Second move for xvalues, move in addition to the needed copy for prvalues.
Other points to consider:
Rule-of-thumb: Single-argument non-copy/move ctors should be explicit: You really don't want to have an implicit conversion from int to Base...
You forgot to re-implement swap for Derived (swap all sub-objects, both base and member). You might forego it if Derived does not add any members though.

Overloading binary operator> in a derived class in c++

I have searched far and wide for a specific answer to this question, and cannot find it. I am trying to create a base class with a virtual operator> that I can override in the derived class. Currently I'm having problems because declaring the function only requires one input variable (as in "bool operator> (Derived & a)" but attempting to define it in a cpp file tells me that it requires two inputs (as in "bool operator> (Derived & a, Derived & b))
I've tried defining the operator inline, but then I get errors where it thinks the derived class is still abstract because I'm passing in the derived type to the operator as shown above, instead of the base class. But if I pass the base class, then I cannot access the derived member variables I need to make the comparison.
I think I'm missing something simple here but I cannot seem to figure out what it is.
Hopefully you can help.
Thanks
For virtual calls to work from a reference/pointer of the base, you will need to use the base-type in the function, so for example
class Derived : public Base
{
....
bool operator>(Base &a)
{
Derived *pa = dynamic_cast<Derived *>(&a);
return this->something > pa->something; // Or whatever...
}
....
};
If you change the type, it becomes a different function, and when you use the base pointer or reference to refer to operator>, it will use the one in the base-class.
Why don't you leave operator>() non-virtual, und have it call a private virtual function?
Like so:
class Base {
public:
bool operator>(Base &a) {
return implementingFunction(a);
}
private:
virtual bool implementingFunction(Base &a) = 0;
};
#include <iostream>
using namespace std;
class base{
public :
virtual bool operator> (base& obj) { cout<<"b\n";return true;}
virtual ~base(){}
};
class derived: public base{
public:
virtual bool operator> (derived& obj) { cout<<"d\n";return true;}
~derived(){}
};
int main()
{
base *a=new derived(),b;
if(*a>b) { delete a; cout<<"Done!\n"; }
return 0;
}
Old question, but I've hardly seen a useful/correct answer here, so I would add my suggestion:
struct base
{
virtual ~base() = default;
virtual bool operator> (base const& obj) const = 0;
};
struct derived: public base
{
derived(int member) : member(member) {}
int member = 0;
virtual bool operator> (base const& obj) const
{
return member > static_cast<derived const&>(obj).member;
}
};
int main()
{
//in reality one would use a unique_ptr, of course
base* a = new derived(1);
base* b = new derived(0);
if(*a > *b)
{
//do something
}
return 0;
}
Caution: this works safely only if you're sure that the base const& parameter is really a derived const& (as e.g. in CRTP).
If not, you should use a dynamic_cast and add some error handling.

calling operators of base class... safe?

Is following pattern ok/safe ? Or are there any shortcomings ?
(I also use it for equality operators)
Derived& operator=(const Derived& rhs)
{
static_cast<Base&>(*this) = rhs;
// ... copy member variables of Derived
return *this;
}
This is fine, but it's a lot more readable IMHO to call the base-class by name:
Base::operator = (rhs);
Yes, it's safe.
A different syntax to do the same thing could be:
Base::operator=( rhs );
That's better to use
Base::operator=(rhs);
because if your base class have a pure virtual method the static_cast is not allowed.
class Base {
// Attribute
public:
virtual void f() = 0;
protected:
Base& operator(const Base&);
}
class Derived {
public:
virtual void f() {};
Derived& operator=(const Derived& src) {
Base::operator=(src); // work
static_cast<Base&>(*this) = src; // didn't work
}
}