I have a base class Base and a derived class D, and I'd like to have move constructor and move assignment operator automatically generated by the compiler for me. Following the Rule of Zero, I leave all memory management to the compiler and only use level-2 classes (no raw pointers, arrays, etc.):
#include <iostream>
class Base{
public:
Base(): a_(42) {}
virtual void show() { std::cout << "Base " << a_ << std::endl; }
private:
int a_;
};
class D : Base {
public:
D(): b_(666) {}
void show() { std::cout << "D " << b_ << std::endl; }
private:
int b_;
};
int main() {
Base b;
b.show();
D d;
d.show();
return 0;
}
This should be it, right?
Enter the C++ core guidelines:
A base class destructor should be either public and virtual, or protected and nonvirtual.
Ah, so I guess I'll have to add a destructor to Base. But that'll do away with the automatically generated move functions!
What's the clean way out here?
You can = default everything that you would like to be generated by the compiler.
See (at the bottom): http://en.cppreference.com/w/cpp/language/rule_of_three
In your case it could look something like:
class Base{
public:
Base(): a_(42) {}
Base(const Base&) = default;
Base(Base&&) = default;
Base& operator=(const Base&) = default;
Base& operator=(Base&&) = default;
virtual ~Base() = default;
virtual void show() { std::cout << "Base " << a_ << std::endl; }
private:
int a_;
};
You can create once a class like
struct VirtualBase
{
virtual ~VirtualBase() = default;
VirtualBase() = default;
VirtualBase(const VirtualBase&) = default;
VirtualBase(VirtualBase&&) = default;
VirtualBase& operator = (const VirtualBase&) = default;
VirtualBase& operator = (VirtualBase&&) = default;
};
And then follow rule of zero:
class Base : VirtualBase
{
public:
Base(): a_(42) {}
virtual void show() { std::cout << "Base " << a_ << std::endl; }
private:
int a_;
};
Related
I am working on a system where a class has a private member that is a base class pointer. The pointer can be pointing to an inherited class object. I would like the parameterized and copy constructors to be able to take a pointer of the base class type and deep copy it without erasing the inherited type. Here is some code I made to demonstrate this problem; I would like c2 and c3 to call B.print instead of A.print, but can't figure out how.
#include <iostream>
class A
{
protected:
double a;
double b;
public:
A()
{
a = 0.0;
b = 0.0;
}
A(double a, double b)
{
this->a = a;
this->b = b;
}
A(const A& copy)
{
a = copy.a;
b = copy.b;
}
virtual void print()
{
std::cout << "print A" << std::endl;
std::cout << "a: " << a << ", b: " << b << std::endl;
}
};
class B : public A
{
private:
double c;
public:
B()
{
c = 0.0;
}
B(double a, double b, double c) : A(a, b)
{
this->c = c;
}
B(const B& copy) : A(copy)
{
c = copy.c;
}
virtual void print()
{
std::cout << "print B" << std::endl;
std::cout << "a: " << a << ", b: " << b << ", c: " << c << std::endl;
}
};
class C
{
private:
A* a;
public:
C()
{
a = nullptr;
}
C(A* a)
{
this->a = new A(*a);
}
C(const C& copy)
{
a = nullptr;
if (copy.a != nullptr)
a = new A(*copy.a);
}
~C()
{
delete a;
a = nullptr;
}
void print()
{
if (a != nullptr)
a->print();
}
};
int main()
{
A* a = new A(3.5, 4.5);
A* b = new B(3.5, 4.5, 5.5);
C c1(a), c2(b), c3(c2);
delete a, b;
c1.print();
c2.print();
c3.print();
}
I have tried including an enum of the available types and storing that value separately, but that program was non-extensible as it would require changing a switch and enum for each added inherited type.
Your actual problem is with these lines:
C(A* a) {
this->a = new A(*a);
}
C(const C& copy) {
a = nullptr;
if (copy.a != nullptr)
a = new A(*copy.a);
}
which explicitly create an object with dynamic type A, ignoring the dynamic types of a and copy.a.
The usual pattern for copying something's real dynamic type is
struct Base
{
// copy ctor etc. as usual
virtual Base* clone() const { return new Base(*this); }
};
struct Derived: Base
{
virtual Base* clone() const { return new Derived(*this); }
};
Other, miscellaneous notes:
You don't need to burn 6 lines on a default constructor that does nothing any more. Just write
class A
{
protected:
double a{};
double b{};
and let the compiler default it. You can default most of your copy constructors too.
If you're controlling pointer lifetime (as C is), just use std::unique_ptr. It's there, it's free, it's much more explicit about your semantics.
When you're owning (ie, controlling the lifetime of) a polymorphic object via a base-class pointer, that base class needs to have a virtual destructor (unless you're doing something exotic with a type-erased deleter, which is out of scope here).
If you've decided to use this->a for data members, use it consistently. If you're only using it for disambiguation, just change the parameter/local variable name so it doesn't collide in the first place.
There are member-naming conventions like m_a or just a_ which make it easy to see which variables are data members, remove ambiguity, and are still less typing/visual noise than randomly sprinkling this-> around.
Working code with only the changes described above:
#include <iostream>
#include <memory>
class A
{
protected:
double a_{};
double b_{};
public:
A() = default;
A(double a, double b) : a_(a), b_(b) {}
A(const A&) = default;
virtual ~A() = default;
virtual A* clone() const { return new A(*this); }
virtual void print()
{
std::cout << "print A" << '\n'
<< "a: " << a_ << ", b: " << b_ << '\n';
}
};
class B : public A
{
double c_{};
public:
B() = default;
B(double a, double b, double c) : A(a, b), c_(c) {}
B(const B&) = default;
virtual B* clone() const override { return new B(*this); }
virtual void print() override
{
std::cout << "print B" << '\n'
<< "a: " << a_ << ", b: " << b_ << ", c: " << c_ << '\n';
}
};
// owns and deep-copies an A.
// class invariant: ptr_ is non-null
//
class C
{
private:
std::unique_ptr<A> ptr_;
public:
explicit C(A* a) : ptr_(a->clone()) {}
C(const C& copy) : ptr_(copy.ptr_->clone()) {}
void print()
{
ptr_->print();
}
};
int main()
{
A a{3.5, 4.5};
B b{3.5, 4.5, 5.5};
C c1(&a), c2(&b), c3(c2);
c1.print();
c2.print();
c3.print();
}
NB. The top-level dynamic allocation was unnecessary even if you do want C to deep copy, so I just removed it entirely instead of either changing it to also use unique_ptr or fixing that incorrect delete statement.
I have following setup:
class A {
public:
constexpr A() = default;
virtual ~A() = default;
virtual void print() const noexcept = 0;
virtual std::unique_ptr<A> clone() const noexcept = 0;
};
class B : public A {
public:
constexpr B() {};
B(const A& a1, const A& a2) : ptr1(a1.clone()), ptr2(a2.clone()) {}
virtual ~B() = default;
virtual void print() const noexcept override {
std::cout << "In B\n";
}
void printPtrs() const noexcept {
ptr1->print();
ptr2->print();
}
virtual std::unique_ptr<A> clone() const noexcept override {
return std::make_unique<B>(*this);
}
private:
std::unique_ptr<A> ptr1;
std::unique_ptr<A> ptr2;
};
class C : public A {
public:
constexpr C() = default;
virtual ~C() = default;
virtual void print() const noexcept override {
std::cout << "In C\n";
}
virtual std::unique_ptr<A> clone() const noexcept override {
return std::make_unique<C>(*this);
}
};
===== MAIN =============
#include "MyClass.h"
#include <vector>
#include <string>
#include <memory>
using namespace std;
int main()
{
C c;
B b;
B B_container(b, c);
B_container.printPtrs();
return 0;
}
I used the 'clone()' method taking the suggestion from this issue: Abstract class and unique pointer
I am getting this error: call to implicitly-deleted copy constructor of 'B'
I am really struggling with this, I don't understand why this copy ctor being called here? Any work around?
B::clone attempts to copy a B object, but B is non-copyable due to its std::unique_ptr members.
Since you have a constructor that accepts two references to A objects and clones them, you could use that instead:
virtual std::unique_ptr<A> clone() const noexcept override {
return std::make_unique<B>(*ptr1, *ptr2);
}
This will create a new B object that holds pointers to copies of the A objects pointed to by this object's unique_ptr members instead of attempting to copy the unique_ptrs themselves, which you cannot do.
I was wondering how should I (or can I? does it make any sense?) overload the assignment operator when working with inheritance and upcasting?
Let's say we have Base class and Derived class (inherited from Base). If i have something like:
/// supose we have one overloaded assignment operator in Base like Base& operator=(const Base&) and
///one in Derived like Derived& operator=(const Derived&)...
Base* a, *b;
Derived c,d;
a = &c;
b = &d;
*a = *b /// this will call the function in Base
If that calls the Base function, why should I overload "=" again in Derived? Is overloading assignment operator in Derived necessary only for working directly with objects, not upcasting (pointers) ?
Here's some code that hopefully helps you out.
Derived Does Not Own A Dynamic Resource
The Base class holds a dynamic resource, so we are required to follow the Rule of 3 (should be 5, but kept it at 3 for brevity). I did so by utilizing the copy/swap idiom.
I then derive Derived from Base. It does not hold a dynamic resource, so I follow the Rule of 0 and don't provide a custom copy constructor, destructor, assignment operator, move constructor, or move assignment.
You can see from the output that the Base portion of the Derived objects are able to deep-copy themsleves just fine, and the Derived-only portion gets by just fine with shallow copy. The final output leaks memory, but I chose to do that to demonstrate an actual overwrite using a pointer to Base.
#include <iostream>
class Base {
private:
int* m = nullptr;
public:
Base() = default;
Base(int v) : m(new int(v)) {}
Base(const Base& other) : m(new int(*(other.m))) {}
virtual ~Base() {
delete m;
m = nullptr;
}
Base& operator=(Base other) {
swap(*this, other);
return *this;
}
friend void swap(Base& lhs, Base& rhs) {
using std::swap;
swap(lhs.m, rhs.m);
}
virtual void print() const {
std::cout << "Address: " << m << "\nValue: " << *m << '\n';
}
};
class Derived : public Base {
private:
double x = 0.0;
public:
Derived() = default;
Derived(double v) : Base(), x(v) {}
Derived(int i, double v) : Base(i), x(v) {}
void print() const override {
std::cout << "Address: " << &x << "\nValue: " << x << '\n';
Base::print();
}
};
int main() {
std::cout << "A\n";
Base* a = new Derived(5, 3.14);
a->print();
std::cout << "\nB\n";
Derived b = *(dynamic_cast<Derived*>(a)); // Copy ctor
b.print();
std::cout << "\nC\n";
Derived c;
c = b;
c.print();
std::cout << "\nReplace A (This leaks)\n";
a = new Derived(7, 9.81);
a->print();
}
Output:
A
Address: 0x21712d0
Value: 3.14
Address: 0x21712e0
Value: 5
B
Address: 0x7ffdd62964c8
Value: 3.14
Address: 0x2171300
Value: 5
C
Address: 0x7ffdd62964b0
Value: 3.14
Address: 0x2171320
Value: 5
Replace A (This leaks)
Address: 0x2171350
Value: 9.81
Address: 0x2171360
Value: 7
Derived Owns A Dynamic Resource
Now, Derived has a dynamic of its own to manage. So I follow the Rule of 3 and provide a copy constructor, destructor, and assignment operator overload. You'll notice that the assignment operator looks identical to the Base version; this is intentional.
It's because I'm using the copy/swap idiom. So in the swap() function for Derived, I add a step where it swaps the Base portion, then swaps the Derived portion. I do this by invoking the Base swap() function through the dynamic cast.
And we can again observe that all objects have their own memory for each dynamically allocated piece.
#include <iostream>
class Base {
private:
int* m = nullptr;
public:
Base() = default;
Base(int v) : m(new int(v)) {}
Base(const Base& other) : m(new int(*(other.m))) {}
virtual ~Base() {
delete m;
m = nullptr;
}
Base& operator=(Base other) {
swap(*this, other);
return *this;
}
friend void swap(Base& lhs, Base& rhs) {
using std::swap;
swap(lhs.m, rhs.m);
}
virtual void print() const {
std::cout << "Address: " << m << "\nValue: " << *m << '\n';
}
};
class Derived : public Base {
private:
double* x = nullptr;
public:
Derived() = default;
Derived(double v) : Base(), x(new double(v)) {}
Derived(int i, double v) : Base(i), x(new double(v)) {}
Derived(const Derived& other) : Base(other), x(new double(*(other.x))) {}
~Derived() {
delete x;
x = nullptr;
}
Derived& operator=(Derived other) {
swap(*this, other);
return *this;
}
friend void swap(Derived& lhs, Derived& rhs) {
using std::swap;
swap(dynamic_cast<Base&>(lhs), dynamic_cast<Base&>(rhs));
swap(lhs.x, rhs.x);
}
void print() const override {
std::cout << "Address: " << &x << "\nValue: " << *x << '\n';
Base::print();
}
};
int main() {
std::cout << "A\n";
Base* a = new Derived(5, 3.14);
a->print();
std::cout << "\nB\n";
Derived b = *(dynamic_cast<Derived*>(a)); // Copy ctor
b.print();
std::cout << "\nC\n";
Derived c;
c = b;
c.print();
std::cout << "\nReplace A (This leaks)\n";
a = new Derived(7, 9.81);
a->print();
}
Output:
A
Address: 0x14812d0
Value: 3.14
Address: 0x14812e0
Value: 5
B
Address: 0x7fffe89e8d68
Value: 3.14
Address: 0x1481320
Value: 5
C
Address: 0x7fffe89e8d50
Value: 3.14
Address: 0x1481360
Value: 5
Replace A (This leaks)
Address: 0x14813b0
Value: 9.81
Address: 0x14813c0
Value: 7
Does the output of this example help clarify your question? You could always override the operator= in the derived class as follows:
#include <cstdio>
struct Base{
virtual ~Base() = default;
virtual void operator=(const Base&) {
std::printf("Base::=\n");
}
};
struct Derived: public Base {
void operator=(const Derived&) {
std::printf("Derived::=\n");
}
void operator=(const Base&) override{
std::printf("Derived::= Base\n");
}
};
int main() {
Base* a, *b;
Derived c,d;
a = &c;
b = &d;
*a = *b; //Dispatches the call to the derived class =
Base base;
Derived derived;
derived = base; //Usual case now after operator=(const Base&) in Derived
c = d; //Usual case
Base base1, base2;
base1 = base2; //Usual case
a = &base1;
b = &base2;
*a = *b; //Usual case
}
Output:
Derived::= Base
Derived::= Base
Derived::=
Base::=
Base::=
I write small example CRTP pattern to better learn it and use it pattern in more complex code.
I want to use CRTP, that base class have access to derived class. All Ok, but i can't create few objects for my base class. If i at first call constructor for both objects Base<Derived1> base1; Base<Derived2> base2;, and at second call function from each object base1.PrintDerived_FromA(); base2.PrintDerived_FromA();, i have result:
Base constr work
Base constr work
b_: 0
b_: 25
but, i should have that:
Base constr work
Base constr work
b_: 9
b_: 25
If i call function right after constructor, all Ok:
Base<Derived1> base1;
base1.PrintDerived_FromA();
Base<Derived2> base2;
base2.PrintDerived_FromA();
Result:
Base constr work
b_: 9
Base constr work
b_: 25
It turns out a new constructor call overrides the existing object, but why? It is possible to fix this? And i want to use only CRTP, no virtual functions.
#include <iostream>
template <class T>
class Base {
public:
Base();
void PrintDerived_FromA();
void InitializeDerived();
};
class Derived1 : public Base<Derived1> {
public:
Derived1(int b);
void PrintDerived();
void SetDerived(int b);
private:
int b_;
};
class Derived2 : public Base<Derived2> {
public:
Derived2(int b);
void PrintDerived();
void SetDerived(int b);
private:
int b_;
};
template <typename T>
Base<T>::Base() {
InitializeDerived();
std::cout << "Base constr work" << std::endl;
}
template <>
void Base<Derived1>::InitializeDerived() {
static_cast<Derived1*>(this)->SetDerived(9);
}
template <>
void Base<Derived2>::InitializeDerived() {
static_cast<Derived2*>(this)->SetDerived(25);
}
template <typename T>
void Base<T>::PrintDerived_FromA() {
static_cast<T*>(this)->PrintDerived();
}
Derived1::Derived1(int b) : b_(b), Base() {
std::cout << "Derived1 constr work" << std::endl;
}
void Derived1::PrintDerived() {
std::cout << "b_: " << b_ << std::endl;
}
void Derived1::SetDerived(int b) {
b_ = b;
}
Derived2::Derived2(int b) : b_(b), Base() {
std::cout << "Derived2 constr work" << std::endl;
}
void Derived2::PrintDerived() {
std::cout << "b_: " << b_ << std::endl;
}
void Derived2::SetDerived(int b) {
b_ = b;
}
int main() {
Base<Derived1> base1;
Base<Derived2> base2;
base1.PrintDerived_FromA();
base2.PrintDerived_FromA();
return 0;
}
static_cast<Derived1*>(this) cast is invalid: this points at object of Base<Derived1> type not at Derived1. So dereferencing produced pointer causes Undefined Behavior. In order for CRTP to work you need to create objects of derived classes.
Imagine these classes:
class Base {
public:
Base() : Base(false)
{ }
virtual ~Base() = default;
void init()
{
cout << "Base::init" << endl;
check();
// ...
}
virtual void check()
{
cout << "Base::check" << endl;
// ...
}
protected:
Base(bool skip_init)
{
cout << "Base::Base" << endl;
if (!skip_init) init();
}
};
class Derived : public Base {
public:
Derived() : Base(true)
{
cout << "Derived::Derived" << endl;
init();
}
virtual ~Derived() = default;
void init()
{
cout << "Derived::init" << endl;
Base::init();
// ...
}
virtual void check() override
{
cout << "Derived::check" << endl;
Base::check();
// ...
}
};
Then constructing a Derived instance would result in
Base::Base
Derived::Derived
Derived::init
Base::init
Derived::check
Base::check
which is exactly what I want to achieve.
It satisfies these requirements:
Base defines init() with operations common to all subclasses and should be used right after construction of whole object (and only there)
init() can contain virtual functions inside, but since it should be called only in the final constructor, it should not cause any harm
check() can be called any time, not only from init() (it should be independent from it), and should always perform all checking, not only those related to the subclass
My best approach so far, as above, was to use protected constructor with flag that avoids calling "incomplete" Base::init() because of virtual functions do not work in superclass constructor. (Without the flag, Base::check() would be called twice.)
My question is: isn't there a better, preferably somehow standard technique, that deals with calling virtual routines after whole object is initialized (pardon for vague terminology)? And of course without requiring users to call init() explicitly (it should stay protected).
One possible use case (mine): Base stands for e.g. an array of general mathematical formulas which must satisfy several constraints. Derived (i.a.) restricts these constraints, add some, can override some particular checks, but mostly still use these from Base. E.g. Base::check_formulas() applies check_formula(f) to every f, and Derived needs to override only check_formula function.
EDIT:
As it is better to avoid virtual functions inside constructors at all, it appears not to be possible to achieve virtual function call from within the object itself, so the object must be constructed "externally" before calling these functions.
Both #StoryTeller and #Caleth suggests deal with this issue, either via dynamic allocation and pointer, or via a function with stack allocation (which is OK with move semantics).
Both of them inspired me to this solution, which is similar to #Caleth's as I found it more simple and straightforward:
template <typename T, typename... Args>
T create(Args&&... args)
{
T t(forward<Args>(args)...);
t.init();
return t;
}
class Base {
public:
virtual ~Base() = default;
Base(const Base& rhs) = default;
Base(Base&& rhs) = default;
Base& operator=(const Base& rhs) = default;
Base& operator=(Base&& rhs) = default;
template <typename T, typename... Args>
friend T create(Args&&... args);
protected:
Base() : _arg(0)
{
cout << "Base::Base()" << endl;
}
Base(int arg) : _arg(arg)
{
cout << "Base::Base(int)" << endl;
}
virtual void init()
{
cout << "Base::init" << endl;
check();
// ...
}
virtual void check()
{
cout << "Base::check" << endl;
// ...
}
private:
int _arg;
};
class Derived : public Base {
public:
virtual ~Derived() = default;
template <typename T, typename... Args>
friend T create(Args&&... args);
protected:
Derived() : Base()
{
cout << "Derived::Derived()" << endl;
}
Derived(int arg) : Base(arg)
{
cout << "Derived::Derived(int)" << endl;
}
void init() override
{
cout << "Derived::init" << endl;
Base::init();
// ...
}
void check() override
{
cout << "Derived::check" << endl;
Base::check();
// ...
}
};
Usage:
cout << endl << "Base() ..." << endl;
Base b1 = create<Base>();
cout << endl << "Base(int) ..." << endl;
Base b2 = create<Base>(5);
cout << endl << "Derived() ..." << endl;
Derived d1 = create<Derived>();
cout << endl << "Derived(int) ..." << endl;
Derived d2 = create<Derived>(10);
Output:
Base() ...
Base::Base()
Base::init
Base::check
Base(int) ...
Base::Base(int)
Base::init
Base::check
Derived() ...
Base::Base()
Derived::Derived()
Derived::init
Base::init
Derived::check
Base::check
Derived(int) ...
Base::Base(int)
Derived::Derived(int)
Derived::init
Base::init
Derived::check
Base::check
Any other suggestions?
Personally, I just won't let anyone construct those objects directly. If their initialization is brittle, there should be another object holding them, and initializing them in its own constructor. I'd do it via the key-pass idiom.
class BaseHolder;
class Base {
private:
void init() {
// do more things
}
friend class BaseHolder;
protected:
class BuildToken {
explicit BuildToken() {}
friend class BaseHolder;
};
Base(BuildToken) {
// do your thing.
}
};
template<typename>
struct MakeType{};
template<typename T>
inline constexpr MakeType<T> make{};
class BaseHolder {
std::unique_ptr<Base> managed;
public:
template<typename T>
BaseHolder(MakeType<T>) : managed(new T(Base::BuildToken())) {
managed->init();
}
};
Now no derived class may call init itself, nor may it be called anywhere besides by Base and BaseHolder. All a derived class has to do is define a c'tor that accepts a BuildToken and forwards it to the base. However, derived classes cannot default initialize BuildToken objects themselves, they can only copy them to forward onto their base. The only place the token can be created is in BaseHolder. This is also the only place where init will be called at the proper time.
The utility MakeType is there for making BaseHolder declaration easier on the eyes, to look like this:
BaseHolder item(make<Derived>);
Don't have any public constructor, but instead have (friend) make_base and make_derived factory functions, which call init on a fully constructed object.
class Base {
public:
virtual ~Base() = default;
Base(const Base &) = default;
Base(Base &&) = default;
Base& operator=(const Base &) = default;
Base& operator=(Base &&) = default;
friend Base make_base() { Base b; b.init(); return b; }
protected:
virtual void init()
{
cout << "Base::init" << endl;
check();
// ...
}
virtual void check()
{
cout << "Base::check" << endl;
// ...
}
Base()
{
cout << "Base::Base" << endl;
}
};
class Derived : public Base {
friend Derived make_derived() { Derived b; b.init(); return b; }
protected:
Derived() : Base()
{
cout << "Derived::Derived" << endl;
}
void init() override
{
Base::init();
cout << "Derived::init" << endl;
// ...
}
void check() override
{
Base::check();
cout << "Derived::check" << endl;
// ...
}
};
init() can contain virtual functions inside, but since it should be called only in the final constructor, it should not cause
any harm.
Even if it's called through the final constructor any of the vtables for calling these virtual functions aren't initialized at that point.
So you can't guarantee the correct intended behavior.
See more elaborations of the problem here please:
Calling virtual functions inside constructors