As the QObject documentation and many others explain, a QObject has an identity and thus hides its copy constructor and assignment operator.
However, I'm not deriving from QObject for its dynamic properties feature or the signals/slots feature. I only want reflection, or the ability to access Foo::staticMetaObject.
class Foo : public QObject {
Q_OBJECT
Q_ENUMS(Color)
public:
enum Color { Blue, Red, Pink };
private:
Color color;
};
Q_DECLARE_METATYPE(Foo::Color)
I then can't copy Foo with:
Foo a;
Foo b;
a = b;
What's the best way to allow copy and assignment in this case? Do I absolutely need to write a copy constructor and assignment operator? What would they look like? Will reflection still work?
If you are only interested in having reflection for
the class name,
enums and flags (Q_ENUMS, Q_FLAGS),
class info (Q_CLASSINFO),
you can use Q_GADGET instead of Q_OBJECT:
class Foo {
Q_GADGET
Q_ENUMS(Color)
public:
enum Color { Blue, Red, Pink };
private:
Color color;
};
which will declare and define Foo::staticMetaObject.
You can certainly implement both a copy constructor and a copy assignment operator in your derived class, but it's likely a sign of bad design. Take this example:
#include <iostream>
class Base {
public:
Base() {}
private:
Base(const Base& other) {
std::cout << "Base copy constructor invoked!" << std::endl;
}
};
class Derived : public Base {
public:
Derived() {}
Derived(const Derived& other) {
std::cout << "Derived copy constructor invoked!" << std::endl;
}
};
int main(int argc, char** argv) {
Derived a;
Derived b = a;
return 0;
}
This will compile just fine. However, as expected, when you run the resulting program, all that is printed is Derived copy constructor invoked!. When the base class declares its copy constructor/copy assignment operator as private, that doesn't prevent derived classes from implementing their own versions. It simply prevents derived classes from calling the base class versions.
And therein lies the problem: it's always good practice to make sure you copy all parts of an object, so that you indeed have two distinct copies. Part of your object includes the data owned by the base class, so you should always make sure to invoke the base class's copy constructor/copy assignment operator to ensure that a full copy is made. But that data is by design non-copyable. Thus, it is impossible to copy all parts of the object.
It's up to you if you want to stick with this design. One important thing to ask yourself is, does your derived class really need to be copyable at all? If not, then there's nothing to worry about!
I don't know much about qt, but if the copy constructor is not allowed then there should be a reason for it (which is discussed in the link you posted). You can change your design not to have it.
Still if you insist then memcpy can be your last resort. I don't recommend it personally, because you have to take care about deep copying, vtable etc. which are not always trivial.
Related
I'm trying to reset a full class with a virtual dtor.
Class Foo has lot's of data members, it would be easier to reset them all at once
class Foo : public QOject
{
public:
Foo() = default;
Foo(Foo&& rhs) = default;
Foo(Foo& rhs) = default;
Foo& operator=(const Foo& rhs) = default;
Foo& operator=(Foo&& rhs) = default;
private:
///lots of data members here
}
Since QOject has a virtual dtor no default constructors/operators are generated for Foo
When calling
mg_foo = Foo();
the compiler fails to generate a copy operator because QObject has virtual functions
I can't use pointers as well since at application startup I'm passing a raw address to QML
QQmlApplicationEngine engine;
engine.rootContext()->setContextProperty("foo", &mg_foo);
If I use a pointer and change the address of mg_foo at runtime (with a brand new initialised class) my application crashes.
How would you handle such problem?
Check the QT documentation for the QObject class:
QObject has neither a copy constructor nor an assignment operator. This is by design. Actually, they are declared, but in a private section with the macro Q_DISABLE_COPY(). In fact, all Qt classes derived from QObject (direct or indirect) use this macro to declare their copy constructor and assignment operator to be private. The reasoning is found in the discussion on Identity vs Value on the Qt Object Model page.
The main consequence is that you should use pointers to QObject (or to your QObject subclass) where you might otherwise be tempted to use your QObject subclass as a value. For example, without a copy constructor, you can't use a subclass of QObject as the value to be stored in one of the container classes. You must store pointers.
So the compiler will fail to generate the copy and assignment operators no matter what you do. You might also want to note that the QObject's only constructor is QObject::QObject(QObject* parent=nullptr). Looking at the documentation, this means that every instance of Foo you create (with your compiler-generated default constructor) will be a top-level window.
As for what to do regarding "resetting" the class, you will have to be more specific about what you are looking for there.
If I understand the problem well, resetting the many data members should be very easy. Just put all the "many" data members to a private data class/struct.
class Foo : public QObject
{
public:
// ... public stuff
void reset();
private:
struct FooPrivate
{
// all the "many" data members with their default values
};
FooPrivate m_data;
};
void Foo::reset()
{
m_data = FooPrivate{}; // this resets the data
}
Yes the drawback is that you have to access all the members via m_data. But it is the price you pay for that you can reset the data in one line.
Btw. If I had too many data members in my class I would think twice about the design. It suggests that the class may have too much responsibility. And you know the rules: one class, one responsibility. Maybe you should change the overall design and split the class into two or more.
This question already has answers here:
How to declare copy constructor in derived class, without default construcor in base?
(3 answers)
Closed 5 years ago.
I confused by compiler warning. I used MinGW 5.3.0 32bit and i try to compile this code:
#include <QCoreApplication>
#include <QObject>
#include <QDebug>
class A : public QObject
{
Q_OBJECT
public:
A(QObject* parent = 0){ Q_UNUSED(parent);}
~A() {qDebug()<<"~A()";}
virtual void func(){}
private:
};
class B : public A
{
Q_OBJECT
public:
B(){}
B (const B & object) {/*do somthing*/}
~B(){}
void func(){/*do somthing*/}
private:
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
return a.exec();
}
My compiler tell me:
In copy constructor 'B::B(const B&)':
WARNING: base class 'class A' should be explicitly initialized in the copy constructor [-Wextra]
B (const B & object) {/do somthing/}
^
Whats wrong?
For a hand-rolled copy constructor (i.e. your B::B(const B &)) it is unusual (although not technically illegal in standard C++) in practice to rely on the default constructor of A being invoked - which is what will happen if you implement the copy constructor of B without explicitly initialising the A in the initialiser list of B constructor.
Your compiler is configured to warn about such things. That is a quality-of-implementation concern for compilers (they are not required to issue warnings in cases like this). But, practically, your compile vendor is doing you a favour.
Your copy constructor of B
B (const B & object) {/*do somthing*/}
is actually equivalent to
B (const B & object) : A() {/*do somthing*/}
which, as I said above, is unusual to explicitly do in practice - it is rarely a desirable behaviour.
The way to shut your compiler up, so it doesn't issue this warning, is to explicitly construct A in the initialiser list of Bs constructor. You could do it like the above using the default constructor of A (which, theoretically, may or may not stop the compiler complaining), but the more usual technique is something akin to
B (const B & object) : A(object) {/*do somthing*/}
Bear in mind that the copy constructor of A will be invoked before the body of B constructors (i.e. base classes are constructed first).
Even better, you would be better off not defining a copy constructor at all, if possible. In that case (assuming something doesn't prevent it from doing so, such as a private copy constructor of a base class) the compiler will automatically generate a copy constructor for B that initialises all its base classes using their copy constructors (recursively) and all its data members.
The problem here is that your class B inherits from A that itself inherits from QObject class which is not designed to be copyable.
Therefore you cannot call the QObject copy constructor in your class A copy constructor provided you have implemented one.
You can still call the default constructor from A in B copy ctor B (const B & object) : A() or even B (const B & object) : A(object) but it will never construct an exact copy of your object.
See http://doc.qt.io/qt-5/object.html#identity-vs-value for more detailed explanation of Qt's choice.
You are writing copy constructor for class B but your parent, class A is default constructed. I (and presumably - compiler as well) would expect B's copy constructor to also copy-construct its parent. And given a fact that you have destructor and a virtual function in A you should seriously consider either creating copy constructor for A or disabling it altogether.
I thought in theory the answer to this question was yes.
However, in practice, my compiler (VS2010) does not seem to complain in the following situation: I have an abstract base class providing some common interface (yet having no data members) and various sub and subsubclasses derived from it.
class Base
{
public:
Base() {}
virtual ~Base() {}
virtual void interfaceFunction1() = 0;
virtual void interfaceFunction2() = 0;
private:
Base(const Base&); // all derived classes should be uncopyable
Base& operator=(const Base&);
// no data members
};
My compiler found it unproblematic to even implement full copy constructors in sub- or subsubclasses.
How can I make sure that every class derived from Base is uncopyable?
edit: If I understand well, this is exactly what Scott Meyers explained in item 6 of Effective C++ (3rd edition, 2005) with his idea of the class Uncopyable (only extended here to a full interface class). What is the difference that makes his idea work ? (I know that he inherits privately, but this should not pose a problem)
This should prevent the compiler from generating a copy constructor for derived classes which do not declare one explicitly. However, nothing prevents a derived class from explicitly declaring a copy constructor which will do something else than call the copy constructor of Base.
There is no way to make sure derived classes are instantiable but not copyable.
Rather than declaring the copy constructor/operator as private declare them as deleted. Declaring copy constructor/operator as private is not the best solution to making the derived classes non-copyable. If you want the base class to be completely non-copyable then declare the copy constructor/operator as deleted as copy can still take place inside the member functions of Base as private members are accessible to that class's functions. You can use the C++11 feature of delete:
Base(const Base&) = delete; // copy constructor
Base& operator=(const Base&) = delete; // copy-assignment operator
But declaring copy constructor/operator as private is also right as long as you're aware that copy can still take place inside the member functions of Base.
In C++11 and later there is the option to declare a constructor deleted.
struct X {
X( const X& ) = delete;
};
Now, anything derived from X that rely on the copy-constructor will not compile.
This is most useful when you want to avoid problems because the compiler auto-generates constructors...
I have a class (class A) which inherits another class (class B).
class A: public B
Class B disabled copy construct and assignment operator (due to not allow a copy).
private:
B(const B&);
B& operator=(const B&);
My question is that should I also disable copy construct and assignment operator in the derived class as well or is it okay if I did not define both.
Subclasses should have the same or stricter [preconditions, post conditions and invariants] than their parent classes. This is the Liskov Substitution Principle. So, you should not re-enable copy construction etc/whatever in the derived class, since you will be loosening the contract of the base class.
If you find you need to do it (or would really like to do it), then it may be a sign that you need to rethink your design.
The question is rather, should you re-enable it. If any base or member is noncopyable, your class will be noncopyable by default. Generally, you won't want to remove it, because it will be difficult or impossible to give it reasonable semantics. But there are notable exceptions: if the base class is abstract, for example, you may want to enable the copy constructor (but not assignment) in the derived class in order to support cloning.
Disallowing copy-constructor and assignment operator of base class will cause that the copy-constructor and assignment operator of derived class won't be usable as well:
class B {
public:
B() { }
private:
B(const B&);
B& operator=(const B&);
};
class A : public B { };
In this case you don't need to explicitly disallow these for derived class, since the default implementation will have to use the parent's implementation first. So if you don't try to access these in your code:
int main() {
A a;
}
it will be perfectly valid. However if you try to copy:
int main() {
A a;
A a2 = A(a);
}
compiler will complain about class A trying to access private members of B (however semantically the second scenario shouldn't happen).
Why do people define a private copy constructor?
When is making the copy constructor and the assignment operator private a good design?
If there are no members in the class which are pointers or handles to a unique object (like file name), then wat other cases are there where private copy constructor is a good idea?
Same question apply for assignment operator. Given that majority of C++ revolves around copying of objects and passing by reference, are there any good designs which involve private copy constructor?
One use case is the singleton pattern where there can only be exactly one instance of a class. In this case, you need make your constructors and assignment operator= private so that there is no way of creating more than one object. The only way to create an object is via your GetInstance() function as shown below.
// An example of singleton pattern
class CMySingleton
{
public:
static CMySingleton& GetInstance()
{
static CMySingleton singleton;
return singleton;
}
// Other non-static member functions
private:
CMySingleton() {} // Private constructor
~CMySingleton() {}
CMySingleton(const CMySingleton&); // Prevent copy-construction
CMySingleton& operator=(const CMySingleton&); // Prevent assignment
};
int main(int argc, char* argv[])
{
// create a single instance of the class
CMySingleton &object = CMySingleton::GetInstance();
// compile fail due to private constructor
CMySingleton object1;
// compile fail due to private copy constructor
CMySingleton object2(object);
// compile fail due to private assignment operator
object1 = object;
// ..
return 0;
}
Some objects represent particular entities that can't or shouldn't be copied. For example, you may prevent copying of an object that represents the log file used by an application, corresponding to the expectation that a single log file will be used by all parts of the code. Use of an accidentally or inappropriately copied object could lead to out-of-order content appearing in the log, inaccurate records of current log size, multiple attempts (some failing) to "roll" to a new log filename or rename the existing one.
Another use is to enforce copying via a virtual function. As constructors can't be virtual, a common practice is to prevent direct access to the copy constructor and provide a virtual Base* clone() method that returns a copy of the actual run-time type to which a pointer points. This prevents the accidental slicing that Base b(derived) would exhibit.
Another example: a dead-simple smart pointer object that simply deletes the pointer it's given in the constructor: if it doesn't support reference counting or some other manner of handling multiple owners, and doesn't want to have risk awkward unintended std::auto_ptr style transfer of ownership, then simply hiding the copy constructor gives a great little smart pointer that's fast and efficient for the limited cases where it's usable. A compile time error about attempting to copy it would effectively ask the programmer "hey - if you really want to do that change me to a shared pointer, otherwise back off!".
A very bad example:
class Vehicle : { int wheels; Vehicle(int w) : wheels(w) {} }
class Car : public Vehicle { Engine * engine; public Car(Engine * e) : Vehicle(4), engine(e) }
...
Car c(new Engine());
Car c2(c); // Now both cars share the same engine!
Vehicle v;
v = c; // This doesn't even make any sense; all you have is a Vehicle with 4 wheels but no engine.
What does it mean to "copy" a car? (Is a car a car model, or an instance of a car? Does copying it preserve the vehicle registration?)
What does it mean to assign a vehicle to another one?
If the operations are meaningless (or merely unimplemented), the standard thing to do is to make the copy constructor and assignment operator private, causing a compile error if they're used instead of weird behaviour.
A common reason to make copy constructor and copy assignment private is to disable default implementation of these operations.
However, in C++ 0x there are special syntax =delete for such purpose.
So in C++ 0x making copy ctor private seems to be resrtricted to very exotic cases.
Copy ctors and assignments are rather syntactic sugar; so such a "private sugar" seems as symptom of greed :)
Even if the contents of the object aren't pointers or other references, preventing people from copying the object can still be useful. Perhaps the class contains a lot of data, and copying is too heavyweight of an operation.
The "virtual constructor idiom" is an important case where a private or protected copy constructor is needed. A problem arises in C++ where you are given the pointer to a base class, of an object that is actually inherited from this base class, and you want to make a copy of it. Calling the copy constructor would not call the copy constructor of the inheriting class, but actually call the copy constructor of the base class.
Observe:
class Base {
public:
Base( const Base & ref ){ std::cout << "Base copy constructor" ; }
};
class Derived : public Base {
public:
Derived( const Derived & ref ) : Base(ref) { std::cout << "Derived copy constructor"; }
}
Base * obj = new Derived;
Base * obj2 = new Derived(*obj);
The code above would produce the output:
"Base copy constructor"
This is clearly not the behaviour the programmer wanted! The programmer was attempting to copy an object of type "Derived" but instead got back an object of type "Base"!!
The issue is rectified by using the aforementioned idiom. Observe the example written above, re-written to use this idiom:
class Base {
public:
virtual Base * clone () const = 0; //this will need to be implemented by derived class
protected:
Base( const Base & ref ){ std::cout << "Base copy constructor" ; }
};
class Derived : public Base {
public:
virtual Base * clone () const {
//call private copy constructor of class "Derived"
return static_cast<Base *>( new Derived(*this) );
}
//private copy constructor:
private:
Derived( const Derived & ref ) : Base(ref) { std::cout << "Derived copy constructor"; }
}
Base * obj = new Derived;
Base * obj2 = obj->clone();
The code above would produce the output:
"Base copy constructor"
"Derived copy constructor"
In other words, the object that was constructed in of desired type "Derived", and not of the type "Base"!
As you can see, in the Derived type, the copy constructor was intentionally made private, because it would be bad API design to give programmers to ability to accidentally try to call the copy constructor manually, rather than using the clever interface provided by clone(). Put another way, a directly callable public copy constructor available could cause programmers to make the mistake mentioned in part 1. In this case, best practise would have the copy constructor be hidden from view, and only indirectly accessible by using the method "clone()".
You might want to implement some of the methods of the class using a copy constructor, but not to expose it outside of the class. So then you make it private. Like any other method.