I get the following error message:
conversion from ‘BaseClass’ to non-scalar type ‘DerivedClass’ requested
while compiling something like:
AnotherClass response;
DerivedClass message = response.serialize(QString("someStuff"));
where I have
BaseClass AnotherClass::serialize( const QString& valueName ) const
and
class DerivedClass : public BaseClass
{
...
DerivedClass &operator=(const BaseClass &other);
}
Can someone explain what is wrong here, and more importantly why?
DerivedClass message = response.serialize(QString("someStuff"));
This is copy-initialization, not assignment, and operator= doesn't even come in play.
You either need a constructor that takes BaseClass or write it like this:
AnotherClass response;
DerivedClass message;
message = response.serialize(QString("someStuff")); // assignment
Besides using copy-initialization, not assignment as you think you are, you are also violating the rule of three/four.
The rule is that if you have any of the below, you must have all of them (either implemented or deleted using Q_DECL_EQ_DELETE):
Destructor
Copy Constructor
Move Constructor (for C++11)
Assignment Operator
For example, suppose you don't want to implement assignment. You should have:
class MyClass {
// private, deleted - compatible with both C++11 and C++98/03.
MyClass & operator=(const MyClass &) Q_DECL_EQ_DELETE;
public:
MyClass(const MyClass &);
MyClass(MyClass &&);
virtual ~MyClass();
...
};
Related
I am new to C++ and from what i learned until now is when we call a copy constructor from a Derived class, The copy constructor of the Base class is called. Let's say that i have a copy constructor in the private area of the Base class. How can i call the copy constructor of the Derived class without calling the copy constructor of the Base class? (In this code A doesn't have the implementation of the copy constructor and this is what i would like to know).
class NonCopyable
{
protected:
NonCopyable(){}
~NonCopyable(){}
private:
NonCopyable(const NonCopyable& nonCopyable);
NonCopyable& operator=(const NonCopyable& nonCopyable);
};
class A: public NonCopyable
{
};
The simple answer is: yes, this is possible.
You only need to define a dedicated Derived copy-constructor that does not call the NonCopyable copy-constructor (of course this might be just confusing in a real software application, but this is a different issue):
This class is constructible, but not copy-constructible:
class CannotBeCopied: public NonCopyable {};
This class is constructible, and also copy-constructible:
class CanBeCopied: public NonCopyable {
public:
CanBeCopied() = default; // needed since otherwise CopyConstructor is only known construtor
CanBeCopied(const CanBeCopied& b) { } // calls NonCopyable::NonCopyable() default-constructor, which is just protected
};
See life example here:
http://coliru.stacked-crooked.com/a/60c9fc42fa2dd59a
After some search I found a way. There is a way to call a copy constructor of the Derived class without calling the copy constructor of the Base class. All what we have to do is to build the copy constructor in A, and A inherit the constructor of NonCopyable while the copy constructor is private:
class NonCopyable
{
protected:
NonCopyable(){}
~NonCopyable(){}
private:
NonCopyable(const NonCopyable& nonCopyable);
NonCopyable& operator=(const NonCopyable& nonCopyable);
};
class A: public NonCopyable
{
public:
A(){}
A(const A& other){}
};
If I have an abstract base class and I want to make all derived classes noncopyable and nonmovable is it sufficient to declare these special member functions deleted in the base class? I want to ensure that my entire class hierarchy is noncopyable and nonmovable and am wondering if I can get away with not having to declare those 4 special member functions as deleted in every derived class. I saw a SO answer where it seemed to imply that a derived class could explicitly declare a copy or move constructor despite being deleted from the base class but the following example results in a compilation error when I try to define a defaulted copy assignment operator so I'm unsure. This is the error:
derived_class.cc:15:15: error: defaulting this copy constructor would delete it after its first declaration
DerivedClass::DerivedClass(const DerivedClass &) = default;
derived_class.h:9:22: note: copy constructor of 'DerivedClass' is implicitly deleted because base class 'virtual_functions::BaseClass' has a deleted copy constructor
class DerivedClass : public BaseClass {
base_class.h:11:3: note: 'BaseClass' has been explicitly marked deleted here
BaseClass(const BaseClass &) = delete;
// base_class.h
class BaseClass {
public:
BaseClass(const BaseClass &) = delete;
BaseClass(BaseClass &&) = delete;
BaseClass &operator=(const BaseClass &) = delete;
BaseClass &operator=(BaseClass &&) = delete;
virtual ~BaseClass() = default;
virtual bool doSomething() = 0;
protected:
BaseClass(std::string name);
private:
std::string name_;
};
// derived_class.h
class DerivedClass : public BaseClass {
public:
DerivedClass();
DerivedClass(const DerivedClass &);
bool doSomething() override;
};
// derived_class.cc
DerivedClass::DerivedClass(const DerivedClass &) = default;
You cannot prevent a child class from defining its own copy/move constructor. That said, it will prevent it "out of the box", meaning if you do not provide one, or use a inline default constructor, it will also be marked as deleted. The reason you get a error here when you try to just define the constructor as default is because you are not allowed to do that in an out of line definition when a member or base has implicitly deleted it. Had you used
class DerivedClass : public BaseClass {
public:
DerivedClass(const DerivedClass &) = default;
bool doSomething() override;
};
then the code would compile, and you would only get an error if you actually try to call the copy constructor. This works because an inline implicit default is allowed even when a member or base implicitly deletes it and the end result is the constructor is implicitly deleted.
Is deleting copy and move constructors/assignment operators in base class enough?
It is enough to prevent implicitly generated copy and move constructors/ assignment operators.
I saw a SO answer where it seemed to imply that a derived class could explicitly declare a copy or move constructor despite being deleted from the base class
This is correct. You cannot prevent this. Well, you can prevent this by declaring the class final. Then there cannot be derived classes, and thus derived classes cannot be copyable.
Of course, such explicitly declared copy constructor (and other) will not be able to copy the base sub object that is non-copyable. The constructors must use BaseClass(std::string) and the assignment operators cannot modify the state of the base object in any way (unless they use some trick to get around access specifier encapsulation).
You cannot prevent a derived class to declare copy/move constructors, but they cannot be defaulted: the default copy ctor or a derived class would try to call the copy ctor of its base (same for move).
But the derived class can explicitely construct its base with its default ctor:
class DerivedClass : public BaseClass {
public:
DerivedClass();
DerivedClass(const DerivedClass &): BaseClass() {
// copy ctor for the derived part
}
bool doSomething() override;
};
Et voila... the class DerivedClass is now copyable despite its base class is not!
I have a problem dealing with deprecated since C++11 default generation of copy constructor and copy assignment operator when there is a user-defined destructor.
For most sufficiently simple classes default-generated constructors, operators and destructor are fine. Consider the following reasons to declare destructor:
Making trivial destructor virtual in base class:
// header
class Base1 { public: virtual ~Base1() = default; };
class Base2 { public: virtual ~Base2(); };
// source
Base2::~Base2() = default;
Would all 4 copy and move special methods be generated by compiler in these cases? If yes, then I think it is fine and there is no need to complicate Base1 or Base2.
Printing debug message in destructor:
// header
class D { public: ~D(); };
// source
D::~D() {
#ifdef DEBUG_THIS
std::cout << "D was destructed." << std::endl;
#endif
}
I believe that in this case copy constructor and assignment operator would be generated; but move constructor and assignment operator would not. I want to avoid using deprecated default-generating and disable copying of D. I also want to avoid flooding D with 4 deleted declarations. Is disabling only one copy constructor enough? Is it a good style?
With C++11, a clean way is to follow the pattern used in boost (see here)
You basically create a base class where copy constructor and copy assignment are deleted, and inherit it:
class non_copyable
{
protected:
non_copyable() = default;
~non_copyable() = default;
non_copyable(non_copyable const &) = delete;
void operator=(non_copyable const &x) = delete;
};
class MyClass: public non_copyable
{
...
}
Deleting the copy-constructor and copy-assignment operator is the simplest and clearest way to disable copying:
class X
{
X(X const &) = delete;
void operator=(X const &x) = delete;
};
I don't follow what you are talking about with virtual destructors in the question body . It sounds like you're asking for a way to make your code take up fewer characters of source code, but also be more cryptic to anybody looking at it.
If the list of deleted functions bothers you, you could hide them behind a macro, I guess.
#define NON_COPYABLE_NOR_MOVABLE(T) \
T(T const &) = delete; \
void operator=(T const &t) = delete; \
T(T &&) = delete;
Only copy constructor and copy assignment operator will be generated when destructor is explicitly defaulted. And even then their generation is deprecated. So, in order to have virtual destructor and all default methods, one should write the following:
struct Base
{
Base()=default;
virtual ~Base() = default;
Base(const Base&)=default;
Base& operator=(const Base&)=default;
Base(Base&&)=default;
Base& operator=(Base&&)=default;
};
I would definitely use a macro for more than one such Base class.
In case when destructor is defined by user, 2 special methods are still generated. There are the following ways to disable deprecated generating copy constructor and copy assignment operator:
delete move constructor OR move assignment operator (not quite self-explanatory but very short):
Base(Base&&)=delete; // shorter than deleting assignment operator
delete both copy constructor and copy assignment operator:
Base(const Base&)=delete;
Base& operator=(const Base&)=delete;
Note that you have to explicitly declare default constructor if you need it, e.g. Base()=default;.
Macro or inheriting special class can be used as well for this purpose but I personally prefer deleting move constructor to implementing my own macro or base class. When using Qt or boost, I would prefer Q_DISABLE_COPY(Base) and inheriting boost::noncopyable respectively, because they are already implemented, widely known and recognizable.
http://accu.org/index.php/journals/1896 - detailed explanation and rationale for these issues.
You can do it by this(which is used by Caffe: a fast open framework for deep learning):
// Disable the copy and assignment operator for a class.
#define DISABLE_COPY_AND_ASSIGN(classname) \
private:\
classname(const classname&);\
classname& operator=(const classname&)
Usage example:
class CNoCopyable{
public:
CNoCopyable(int i):m_d(i){}
private:
int m_d;
// add this line(pass class name)
DISABLE_COPY_AND_ASSIGN(CNoCopyable);
};
for example, your constructor might look like this:
myClass::myClass(Mesh &mesh) : baseClass(mesh)
{
pointer = new Thing(mesh);
}
mesh is not held in myClass, nor is there a getter for mesh in baseClass where it is held. Is this simply a case of having to implement a getter in the base class?
for example you cannot do this:
myClass::myClass(const myClass& original) : baseClass(mesh) //there is no mesh
{
pointer = new Thing(mesh); //mesh is no longer in the parameter list
}
How does the compiler make this copy when it creates a default copy constructor for such classes? Or is this a case where a copy constructor is necessary? mesh is not a private member of brain, and there is not getter for it so how do we make a new Thing?
EDIT - Updated the problem by adding Thing
mesh has to be copied inside the baseClass copy constructor.
class baseClass
{
Mesh myMesh;
public:
baseClass(const baseClass &other) : myMesh(other.myMesh) {} // <--- copy Mesh
};
class myClass : public baseClass
{
public:
myClass(const myClass& other) : baseClass(other) {} // <--- simply pass
};
Every class will have to take care of its own copying.
The default copy constructor for myClass will simply call the copy constructor for the base class (and for every other member).
The cannonic copy constructor would be:
MyClass::MyClass( MyClass const& other )
: BaseClass( other )
{
}
The copy constructor for BaseClass would take a const reference to
BaseClass, and other would convert implicitly. The copy constructor
for BaseClass would then do whatever was necessary.
This is the implicitly generated constructor, so you don't have to
provide it, provided you're happy with the other aspects of generated
constructors: public and inline.
I want to ensure that the following type of call is illegal:
MyClass me;
MyClass you;
me = you; // how to make this illegal?
Is it possible?
Declare the assignment operator private:
class A {
private:
void operator=(const A&);
...
};
but don't provide an implementation - you will get a compile or link-time error if you try to perform an assignment to A.
I prefer to use a macro to do this. This also prevents copying, by making the copy constructor private too:
#define CANNOT_COPY( class ) \
private: \
class(const class&); \
void operator=(const class &) \
I can then say things like:
class A {
CANNOT_COPY( A );
...
};
which is easy to read and easy to search for.
declare the assignment operator as private.
Yes - define a private assignment operator (operator=) or derive from the handy boost::noncopyable class.
As of C++11, my understanding is that the preferred solution is to use the '= delete' construct:
class MyClass {
MyClass (const MyClass&) = delete; // Disable copy constructor
MyClass& operator=(const MyClass&) = delete; // Disable assignment
...
}
Then
MyClass me;
MyClass you;
me = you; // won't compile
Use const.
MyClass const me;
MyClass you;
me = you; // compilation error
I use to derive my noncopyable classes from a common noncopyable class. If not using boost, I usually use this shortcut:
class NonCopyable
{
protected:
/**
* Protected default constructor
*/
NonCopyable() {}
/**
* Protected destructor
*/
~NonCopyable() {}
private:
/**
* Private copy constructor
*/
NonCopyable( const NonCopyable& );
/**
* Private assignment operator
*/
const NonCopyable& operator=( const NonCopyable& );
};
Note that neither the copy constructor nor the assignment operators have an implementation.
The other answers here are all correct. However, it is important to note that you are only prohibiting the specific code you mentioned. Someone can still come along and make a duplicate of your class by using memcpy or other strategies.