Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Abstract classes and move semantics

According to “Rule Of Five” when I declare one of: copy or move operation or destructor I must write all of them, because the compiler doesn't generate them (some of them) for me. But if my class (A) derives from an abstract class with a virtual destructor, does this mean that the destructor in class A will be considered "user-defined"? As a consequence, will move semantics not work with objects of this class A because compiler won't generate a move constructor for me?

struct Interface {
    virtual void myFunction() = 0;
    virtual ~Interface() {};
};

struct A : public Interface {
    void myFunction() override {};
};
like image 556
NiegodziwyBeru Avatar asked Apr 23 '15 21:04

NiegodziwyBeru


1 Answers

In [class.copy]:

If the definition of a class X does not explicitly declare a move constructor, one will be implicitly declared as defaulted if and only if
(9.1) — X does not have a user-declared copy constructor,
(9.2) — X does not have a user-declared copy assignment operator,
(9.3) — X does not have a user-declared move assignment operator, and
(9.4) — X does not have a user-declared destructor.
[ Note: When the move constructor is not implicitly declared or explicitly supplied, expressions that otherwise would have invoked the move constructor may instead invoke a copy constructor. —end note ]

Interface does have a user-declared destructor, so Interface's move constructor will not be implicitly declared as defaulted. But A doesn't fit any of those bullet points - so it will have an implicit move constructor that is defaulted. A(A&& )will just copy the Interface part, as per the note. We can verify this by adding members to Interface and A:

#include <iostream>

template <char c>
struct Obj {
    Obj() { std::cout << "default ctor" << c << "\n"; }  
    Obj(const Obj&) { std::cout << "copy ctor" << c << "\n"; }
    Obj(Obj&&) { std::cout << "move ctor" << c << "\n"; }
};

struct Interface {
    virtual void myFunction() = 0;
    virtual ~Interface() {};

    Obj<'I'> base;
};

struct A : public Interface {
    void myFunction() override {};

    Obj<'A'> derived;
};

int main() {
    A a1;                      // default I, default A
    std::cout << "---\n";
    A a2(std::move(a1));       // copy I, move A
    std::cout << "---\n";
    A a3(a2);                  // copy I, copy A
}
like image 156
Barry Avatar answered Oct 22 '22 17:10

Barry