What is best practice for move semantics with virtual functions? - c++

So let's say i have interface:
class MyInterface
{
public:
virtual ~MyInterface() = default;
virtual void DoSomething(const MyType& a, const MyTypeB& b);
};
And the thing i want is to allow usage of move semantics if any of function arguments is rvalue or lvalue reference.
What i don't want is to define interface like this:
class MyInterface
{
public:
virtual ~MyInterface() = default;
virtual void DoSomething(const MyType& a, const MyTypeB& b);
virtual void DoSomething(MyType&& a, const MyTypeB& b);
virtual void DoSomething(const MyType& a, MyTypeB&& b);
virtual void DoSomething(MyType&& a, MyTypeB&& b);
};
And the combinatorics get even worse if more parameters added to the method.
So in implementation i basically want to move argument if i got rvalue passed and copy otherwise.
There's std::forward in the standard library, but it works with so called "forwarding reference", which require templates and it's impossible to have template parameters in virtual methods.
Is there any way to do this with preserving the purpose of interface base type and without bloating the interface itself so much?

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?

C++ Polymorphism does not work as expected

Consider the following code:
#include <iostream>
class Base{
public:
int iB;
Base() :iB(0){};
virtual ~Base(){}
virtual void foo(Base&, const int&, const int&) const = 0;
};
class Derived : public Base{
public:
int iD;
Derived() :iD(1){};
void foo(Derived&, const int&, const int&) const;
};
void Derived::foo(Derived& d, const int& i1, const int& i2) const{
std::cout << d.iD;
}
class BaseWrap{
public:
BaseWrap(){};
virtual ~BaseWrap(){};
virtual Base* bar() const = 0;
protected:
Base* b;
};
class DerivedWrap : public BaseWrap{
public:
DerivedWrap(){};
Derived* bar() const;
private:
Derived* d;
};
Derived* DerivedWrap::bar() const {
return new Derived;
}
int main(){
return 0;
}
This results in a compiler error "Error: object of abstract class type "Derived is not allowed" pure virtual function Base::foo" has no overrider.
I assumed that thanks to polymorphism I can always put a pointer to a derived class where a pointer to Base class is expected. Anyway, I tried changing the Derived class to the below:
class Derived : public Base{
public:
int iD;
Derived() :iD(1){};
void foo(Base&, const int&, const int&) const;
};
void Derived::foo(Base& d, const int& i1, const int& i2) const{
std::cout << d.iD;
}
However, now I I get the error "Error: class "Base" has no member "iD".
EDIT:
foo takes a ref to derived because in my real implementation i.e. I want to be able to do this:
Derived d1;
Derived d2;
d1.foo(d2, 0, 1);
Furthermore, I probably should have been more clear on what I am actually asking. I realize that removing the pure virtual function declatation
virtual void foo(Base&, const int&, const int&) const = 0;
fixes the issue. However, in all derived class implementation the code is exactly the same, and only varies in the type of the first argument (derived classes from Base). So it feels like there should be a pure virtual function to enforce existence of foo.
The problem
In your base class you define the pure virtual member function:
virtual void foo(Base&, const int&, const int&) const = 0;
but you provide in the derived a function with another signature:
void foo(Derived&, const int&, const int&) const;
So you have one more member function in the derived class (an overload: same name but different parameter types), but still the inherit the pure virtual function. So the derived class is as abstract as the base class and you're not allowed to instantiate it.
The solution
In the derived class change the signature so that it matches the pure virtual bas e member function:
void foo(Base&, const int&, const int&) const;
By the way, whenever you use virtual functions, use override keyword to spot these kind of subtle errors at compilation, even for ordinary virtual functions:
void foo(Base&, const int&, const int&) const override;
More infos
Indeed, once you define your foo() with a Base parameter, you can't use easily the iD member.
The first solution is to use a dynamic_cast to tell your code that the base is in fact a derived object. Of course you have to check if this assumption is correct:
void Derived::foo(Base& d, const int& i1, const int& i2) const{
Derived *dp = dynamic_cast<Derived*>(&d);
if (dp) {
std::cout << dp->iD;
}
}
However, what is not clear to me is why you need this first in a first place. Why not get rid of this first type dependent parameter and use the member variables of the current object:
void Derived::foo(const int& i1, const int& i2) const{
std::cout << iD;
}
Eventually, I came accross this : What are the differences between a pointer variable and a reference variable in C++?
I conclude that since :
A reference cannot be re-bound, and must be bound at initialization, then the line :
rBase = rDeriv;
only triggers stBase copy operator, it does'nt rebind rBase.
A reference can be seen as an alias to a typed variable => no polymorphism is possible through a reference.

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... :(

returning by value and polymorphism

So I have a storage class that has a ton of basic functionality that is really useful as is. It has move constructors to allow return by value.
class A
{
public:
virtual ~A(){}
A(const A& a);
A(A&& a);
A& operator=(const A& rhs);
A& operator=(A&& rhs);
int foo();//example member function
//example function returning by value, elision and RHR make it efficient
static A Foo();
};
This is great because it allows who own A to be very well defined. If I start needed to have inherited classes that extend A, AND the return statement of a call function to have polymorphism, is the only "correct" way to use smart pointers? AKA
class B_interface : public A
{
public:
virtual ~B_interface(){}
virtual void FooBar() = 0;
};
class B : public B_interface
{
public:
virtual ~B(){}
B(const B& a);
B(B&& a);
B& operator=(const B& rhs);
B& operator=(B&& rhs);
virtual void FooBar() override;
static shared_ptr<B> idontlikeit();
}
I thought of a (probably bad) way to get around it: if, instead of inheritance, use composition: the class contains something akin to a impl ptr:
class B_interface
{
public:
virtual void FooBar() = 0;
};
class B : public A
{
shared_ptr<B_interface> impl_;//could use
public:
B(const A& a,shared_ptr<B_interface> interface)//or some smarter way to pass this in
: A(a)//call a's copy constructor
{
impl_.reset(interface);
}//this constructor thinks
void FooBar() { impl_->FooBar();}
virtual ~B(){}
B(const B& a);
B(B&& a);
B& operator=(const B& rhs);
B& operator=(B&& rhs);
static B ilikeitbetter();
}
So I like using the class better with that one, but making the class kinda stinks with that one...also, the B_interface might not make much sense outside B...Do you guys have any alternatives?
Yes, runtime polymorphism requires dynamic allocation and pointers. Derived classes can be (and usually are) of different size than base classes, so code expecting value semantics would not know how large a block to reserve for the value type.
In this specific case, consider returning a unique_ptr<Interface> if you don't expect the caller to require shared semantics. That way you don't force the caller to do reference counting if they don't need it. (The caller can always transfer ownership from the unique_ptr to a shared_ptr if they want shared semantics)

C++ dynamic binding with overloading

Suppose:
struct A {
virtual int foo(const A& a) const { return 1; }
};
struct B : A {
virtual int foo(const A& a) const { return 2; }
virtual int foo(const B& b) const { return 3; }
};
void testOverloadingBinding(const A& a,const B& b) {
cout << a.foo(b);
}
int main() {
testOverloadingBinding(B(),B());
}
It prints 2. I would assume it prints 3 since this binding is dynamic, and as far as I know overloading has static binding.
Can anyone please explain how the compiler decides which function to invoke here?
This:
virtual int foo(const B& b) const;
is not an override for this:
virtual int foo(const A& a) const;
Therefore it can never be called via a reference to an A.
virtual int foo(const B& b) const;
doesn't override anything, so compiler chooses first function. But, probably in future, we will have a dynamic type resolution, and in this case compiler will choose second function.
For more info, see http://www2.research.att.com/~bs/multimethods.pdf
There is simply no overload available to resolve to. The object you are calling foo on is of type A and in A only one function foo(const A&) exists. The dynamic dispatching yields the function in the base class. In C++ a member function is identified by its name and its arguments. Adding an overload in a base that does not exist in the parent will not enable dynamic dispatch onto it.