I have read many threads regarding this, but I couldn't find an answer to this
In my Qt application, I am using QSignalSpy to catch a signal. It has a user-defined datatype for one of its parameters. To catch such a parameter, I have to first register that datatype with Qt using QMetaType and using the macro Q_DECLARE_METATYPE. It says
This macro makes the type Type known to QMetaType as long as it provides a public default constructor, a public copy constructor and a public destructor. It is needed to use the type Type as a custom type in QVariant.
The problem: I have a class CustomData with only constructor defined. Now unless I explicitly declare a destructor and a copy constructor, Qt throws an error. I want to use the implicit destructor and copy constructor that C++ gives. For destructor, I used
~CustomData() = default;
which uses the default destructor. But I cannot use a similar statement for the copy constructor. Will using
CustomData( const CustomData& ) {};
invoke the implicit copy constructor?
(I am doing this because I want to retain the behavior of the implicit copy constructor)
Thanks in advance.
The CustomData class is shown below
#include <QMetaType>
#include <QString>
class CustomData : public QObject
{
Q_OBJECT
public:
CustomData(QObject *parent = NULL);
~CustomData() = default; // I added this line
//Will the next line call the implicit copy constructor?
CustomData(const CustomData&) {}; //I added this line
enum CustomMode {mode1, mode2, mode3};
void somePublicMethod();
signals:
void completed(CustomData *data);
private slots:
void customComplete();
private:
CustomMode _mode;
QString _path;
CustomData *_chained;
};
Q_DECLARE_METATYPE(CustomData)
In short - it doesn't matter. Your implementation does not(hopefully) cause any effect.
If you go through the Qt documentation, it says as follows
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.
Go through this -- Q_DISABLE_COPY().
This dictates that you use pointers to do the work. Look at this thread which discusses on how to copy object in Qt.
Actually the given code compiles without errors on Visual Studio 2013. However if the signature of the signal is changed to void completed(CustomData data); then a similar error occurs. Since you have not specified the compiler, but I assume it is gcc/clang you could get the error because template handling differs a bit. If so, the error is most likely caused by Q_DECLARE_METATYPE(CustomData) since it tries to generate the copy constructor inside. Change it to Q_DECLARE_METATYPE(CustomData*) (because that is what you really need, you are queuing arguments of type CustomData* not CustomData, at least in the given sample) and if you really have no signals that send the CustomData instances by value you should be fine.
Also, if you are passing the object by pointer then you should use Q_DECLARE_METATYPE(CustomData*). But I'd advise passing it through a std::unique_ptr or std::shared_ptr to prevent memory leaks.
Related
I read that the signal/slot concept in qt should always pass arguments by value instead of reference to ensure that signals/slots work flawlessly between threads.
I now have a piece of code that will only compile when the argument to a signal is emitted by reference, not value:
#include <QObject>
class mythirdclass {
public:
mythirdclass();
};
class mysecondclass : public QObject, public mythirdclass {
public:
mysecondclass(mythirdclass third);
};
class myclass : public QObject {
Q_OBJECT
public:
myclass();
signals:
// not working
void messageReceived(mysecondclass mymessage);
// working
// void messageReceived(mysecondclass &mymessage);
};
myclass::myclass()
{
mythirdclass third;
mysecondclass msg(third);
emit messageReceived(msg);
}
mysecondclass::mysecondclass(mythirdclass third)
{
// DO stuff
}
mythirdclass::mythirdclass()
{
}
The compiler error is:
..\example\main.cpp: In constructor 'myclass::myclass()':
..\example\main.cpp:28:20: error: use of deleted function 'mysecondclass::mysecondclass(const mysecondclass&)'
emit signal(second);
^
..\example\main.cpp:8:7: note: 'mysecondclass::mysecondclass(const mysecondclass&)' is implicitly deleted because the default definition would be ill-formed:
class mysecondclass : QObject, public mythirdclass {
^
Based on the errors I thought abour writing a copy constructor for mysecondclass, however after some attempts I gave up for now, because I didn't get it right.
So my questions are:
why is the compiling failing in the first place?
if it fails because of a missing copy constructor, why is the compiler not able to define one implicitly?
how would the working copy constructor in my case look like?
Thanks in advance.
Why is the compiling failing in the first place?
Because passing by value implies copying, and if the copy-constructor is deleted, then it simply can't pass by value and your function cannot be compiled with this signature, while it can receive its argument by reference because it doesn't involve copying.
If it fails because of a missing copy constructor, why is the compiler not able to define one implicitly?
It actually fails because it hasn't been able to define one implicitly. The reason for that is that your class derives from QObject. And that QObject doesn't have a public or protected copy-constructor, by design. So the compiler cannot define one implicitly.
How would the working copy constructor in my case look like?
Given the nature of QObjects, and the design decision that's behind it when it comes to QObjects not being copyable, I would recommend against using signals and slots that take QObjects or class deriving from it by value (or simply any function that does this, and signals/slots are mainly functions deep down), but instead by reference or by pointer.
For you third question, if you do not want to define a default constructor for mysecondclass, your copy constructor would probably look like
mysecondclass(mysecondclass const &other) : mythirdclass() {
/// stuff
}
For your second question, I suppose (not sure) that the default copy constructor try to use the default constructor that has been automatically deleted because you have defined another constructor of mysecondclass from an object of mythirdclass (I would recommend to you to use a const reference for the parameter here to avoid a useless copy)
There are many C++ programming best practices that are proposed in many articles and books. Following is a subset that is related to C++ class data members:
Make sure that objects are initialized before they are used.
Make sure that all constructors initialize everything in the object.
It is usually more effective to initialize data members in the initializer list of each constructor than in its body.
In the initializer list, data members should be listed in the order they are declared.
Consider the following class with data members of Qt class types:
class MyClass {
public:
myClass();
~myClass();
private:
int myInt;
QString myQString;
QList<QString> myQList;
QHash<int, QString> myQHash;
char * pChar;
};
By applying the above best practices, the constructor code would look like the following:
MyClass::MyClass() :
myInt(0), // OK, primitive should be initialized.
myQString(), // Is this really needed?
myQList(), // Is this really needed?
myQHash(), // Is this really needed?
pChar(NULL) // OK, pointer should be initialized.
{
}
However, I have the impression that not all of the Qt class data members need to be initialized. But I am not 100 % sure of this. Some developers argue that by putting all the data members in the initialization list, we may avoid omitting the initialization of some important data members that should be initialized. However, if this is a real concern, I would prefer putting a comment line for each data member that does not need to be initialized, for example:
MyClass::MyClass() :
myInt(0),
//myQString(),
//myQList(),
//myQHash(),
pChar(NULL)
{
}
To summarize, I would like to know when a Qt class data member should be initialized, and when the initialization is not needed, and why. Thanks!
If you don't have a default constructor of a class then you must initialize it in initializer list, and it is not required to call default constructor in initializer list. It is not Qt specific it is a general rule for any class. When you have a default constructor(which takes 0 argument) even if you don't call it in initializer list, it will be called automatically.
Update:
Q1: Are the 2 versions of MyClass::MyClass() above equivalent? That
is, do they produce 2 objects of same content?
Yes.
Q2: Is one version faster than the other?
You can type the second version faster ;-), there is no performance difference.
Default constructor of QObject's will be called regardless you call it explicitly, or it's called implicitly when your object is created.
You may put a debug message into QObject constructor code and see for yourself, it's Open Source for truth's sake! :)
I have two classes, one has permitted making the only explicitly declared constructor, the no arguments one, private. I recently added another class but am getting compile-time errors due to having made the no argument constructor private. The only difference is the first had a public static factory method while the latter has a non-static constructor which takes an argument.
Thanks, hope this makes some sense.
Okay, I give you some code:
This doesn't compile:
class GridElem {
public:
GridElem(const char _idata);
~GridElem();
private:
GridElem();
}
This does compile:
class GridElem {
public:
GridElem(const char _idata);
~GridElem();
GridElem();
}
This does compile:
class MyClass {
public:
~MyClass();
private:
MyClass();
Not a complete example, sorry, but I believe this shows where the anomally arises, perhaps from extending cocos2d::Layer?
EDIT
Alright I found the call that is doing this (eclipse couldn't find it :()
in header
GridElem myGrid[15][15];
in cpp file
MyClass::MyClass() : myGrid{0} {}
I only recently changed it from a smaller grid and giving each element explicitly (because it was still just 0 for want of more information), I think this must now expand to parameterless c'tor. I completely forgot that, sorry, but it wasn't 100% obvious mistake.
You can always make the default constructor private (or not have a default constructor at all).
What you can't do is use a private default constructor from outside the class (or its friends).
You haven't provided enough context to know for sure, but I suspect your problem is that something else in your code is trying to default construct a GridElem, so it needs to be public.
The only difference is the first had a public static factory method while the latter has a non-static constructor which takes an argument.
If MyScene has a factory method then that's a member and can call the private default constructor. There's no "anomaly", you've just said that both types can only be default constructed by their own member functions (and friends), but only one of them has a member function to actually do that.
making default constructor private usually means you want all
creation to go through a factory. So use said factory, or make it public
I decided to try creating a simple C wrapper for the V8 API using the model described in Developing C wrapper API for Object-Oriented C++ code. Unfortunately, I'm not too familiar with C++, so I'm running into an issue with inherited constructors.
v8capi.h
typedef struct V8Context V8Context;
#ifdef __cplusplus
extern "C" {
#endif
V8Context *V8_NewContext();
#ifdef __cplusplus
}
#endif
v8capi.cpp
#include <v8.h>
struct V8Context : public v8::Handle<v8::Context> { };
V8Context *V8_NewContext() {
v8::HandleScope hscope;
return new V8Context(v8::Context::New());
}
From what I understand, new V8Context(...) should call v8::Handle<T>'s constructor which takes a Handle<T>. v8::Context::New() returns a v8::Persistent<T>, which inherits v8::Handle<T>, so that should work. But in reality, it's trying to call a constructor that takes a const V8Context &:
error C2664: 'V8Context::V8Context' : cannot convert parameter 1 from
'v8::Persistent<T>' to 'const V8Context &'
with
[
T=v8::Context
]
No user-defined-conversion operator available that can perform this
conversion, or the operator cannot be called
What am I doing wrong?
There is no constructor defined in V8Context, so only the implicit copy constructor appears as an option. You need to explicitly define a constructor in V8Context that forwards the v8::Persistent<T> argument to its base class.
Constructors aren't inherited in C++ (although there are some passthrough features in C++11 I believe), so you're going to have to write your own constructor in V8Context that explicitly calls the proper base class constructor.
From what I understand, new V8Context(...) should call v8::Handle<T>'s constructor.
new V8Context(...) will only call a constructor declared in V8Context; constructors are not inherited. You'll need to add one, something like:
V8Context(v8::Handle<v8::Context> const & handle) :
v8::Handle<v8::Context>(handle)
{}
new V8Context(...) doesn't call a constructor from v8::Handle<T>, but a constructor from V8Context. Since you haven't defined one, only the default constructor and copy constructor are availible (constructors aren't inheritable). Therefore it tries to call the copy constructor and fails since the argument can't be converted to V8Context. To solve your problem you need to add an appropriate constructor to V8Context, which forwards the argument to the base constructor (might not be the exact code given, depending how excatly your arguments look like, but similar):
struct V8Context : public v8::Handle<v8::Context> {
V8Context(const v8::Handle<v8::Context>& handle): v8::Handle<v8::Context>(handle) {}
};
Your V8Context only has the compiler generated constructors:
the copy constructor which is synthesized whenever it is needed and not explicitly declared or made impossible (e.g. by deriving from a class without a copy constructor). This constructor take a V8Cintext as argument.
the default constructor which is synthesized when needed, when there is no explicit constructor, and all members and bases can be default constructed. Thos constructor has no arguments.
It seems the type you try to pass doesn't match the signature of the copy constructor. If you want to use it you'll need to explicitly provide a corresponding constructior.
Currently I'm attempting to write my own wxObject, and I would like for the class to be based off of the wxTextCtrl class.
Currently this is what I have:
class CommandTextCtrl : public wxTextCtrl {
public:
void OnKey(wxKeyEvent& event);
private:
DECLARE_EVENT_TABLE()
};
Then later on I have this line of code, which is doesn't like:
CommandTextCtrl *ctrl = new CommandTextCtrl(panel, wxID_ANY, *placeholder, *origin, *size);
...and when I attempt to compile the program I receive this error:
error: no matching function for call to ‘CommandTextCtrl::CommandTextCtrl(wxPanel*&, <anonymous enum>, const wxString&, const wxPoint&, const wxSize&)’
It seems that it doesn't inherit the constructor method with wxTextCtrl. Does anyone happen to know why it doesn't inherit the constructor?
Thanks in advance for any help!
C++ does not inherit constructors (you may be thinking of Python, which does;-). A class w/o explicitly declared ctors, like your CommandTextCtrl, in C++, only has default and copy ctors supplied implicitly by C++ rules.
So, you need to explicitly define a ctor with your desired signature, which basically "bounces back" to the base class's -- with the CommandTextCtrl(...): wxTextCtrl(...) {} kind of syntax, of course.