I want to make a class in my Rhapsody model non-copyable, but
don't have the boost library available (from which I would just derive)
nor can I use the C++11 way of disabling the default generated copy ctor and copy assignment op (because I would need to manipulate the function signature, which AFAIK is not directly possible)
=> so I am doing it the old fascioned way.
What I need from Rhapsody:
In this context, I want to generate only a declaration for copy ctor and copy assignment op - I don't need the implementation.
Is this even possible?
Things that I considered:
I haven't found any helpful property yet.
Mapping only the specification of a member function to a file object won't prevent Rhapsody from generating the empty function body into an implicitly created file object (that I don't need nor want).
I would suggest a stereotype approach:
Create a NonCopyable base class, as, for example, described by #Dennis.
Create a stereotype, you can, for example, name it <<non-copyable>>.
a) Set the stereotype property CPP_CG::Class::AdditionalBaseClasses to NonCopyable (the name of the base class created above).
b) Make the stereotype applicable to classes.
Finally, add the <<non-copyable>> stereotype to all classes that shall be non copyable.
Write a private copy ctor and opertor:
class NonCopy {
// These private versions of the copy constructor
// and operator will signal to the compiler to
// prevent automatic generation.
NonCopy(const NonCopy& other);
const NonCopy& operator=(const NonCopy& other);
public:
// Your public ctors
NonCopy(int a);
}
You can look at the boost version of the non-copyable interface for a more complete example.
This can be done (at least in Rhapsody 8.2.0) using a combination of properties of the constructor. First, set the CG::Operation::Generate property to Specification, then set the CPP_CG::Operation::PostDeclarationModifier to = delete. (Both of these are set at the constructor level). This ensures that no function body is created, and also allows usage of the delete keyword via modification of the function signature.
I have not found a way to write this in code and have Rhapsody interpret it correctly while roundtripping, though.
Related
To my understanding, C++ doesn't feature a mechanism to add methods to an existing class (say, QString but please don't focus on the fact that's a Qt function) as ObjC does; let's assume those new methods do not require any new member variables. Instead, the only option is to create a wrapper class (say, KString) that inherits A and adds the required method(s) (say, toFoo()).
However, this requires modification everywhere where you want to use the new method, either something like
static_cast<KString*>(ptrToQStringInstance)->toFoo()
But if there are many places like that you'd like to be able to use #define QString KString in the relevant files (or do the equivalent search/replace).
Of course then you're going to run into errors like "no viable conversion to [const] KString from [const] QString" for which you'd have to add a copy constructor like
inline KString(const QString &that)
{
*(static_cast<QString*>(this)) = that;
}
// add an assignment operator for good measure too
inline KTEStringView &operator=(const QString &other) Q_DECL_NOTHROW
{
*(static_cast<QString*>(this)) = other;
return *this;
}
My question:
- is there a well-defined and limited set of methods (independent of the parent class) that you'd have to implement (override) this way, or are you looking at overriding all methods that return a QString, trying very hard to avoid deep copies?
- is this the best approach or can you use language constructs that make this more "elegant" (e.g. using or some fancy kind of method assignment)?
Thanks!
Edit: why would you do this: when your existing class comes from an older version of a library, and you working with dependent code that would like to use things from a newer version of that library. In ObjC I have done this kind of extension regularly to add convenience methods to NSWindow or NSString so I could call them as if they were provided by the SDK, without having to cast to a dedicated child class or call a global function that takes the class instance as a parameter.
Edit2: here's another example, this time openly Qt related. It adds an alternative for QQuickItem::size() to Qt versions that do not yet have this:
template <class QtType>
class Q510QI : public QtType
{
public:
#if QT_VERSION < QT_VERSION_CHECK(5, 10, 0)
QSizeF size()
{
return QSizeF(QtType::width(), QtType::height());
}
#endif
};
#define Q510QIPCAST(instanceptr) static_cast<Q510QI<std::decay<decltype(*instanceptr)>::type>* >(instanceptr)
This allows me to replace foo->size() (where foo points to a QQuickItem or inherits it) with Q510QIPCAST(foo)->size().
Evidently I could have done this with a free template function (which would not have needed decltype and std::decay) but that function would need to have an explicit implementation for the newer Qt versions (call the actual QQuickItem::size() method). If I wanted to add a series of other trivial methods I'd be adding as many #if/#else/#endifs whereas here I could just add those trivial functions between that single #if/#endif.
C++ doesn't provide extension methods, as other languages (as C#) might propose.
C++ way is to add free functions or use inheritance.
Uniform function call syntax proposal might allow to have syntax you expect (with free functions way).
I'm reading this Qt doc page about custom types, and it states the following:
The default constructor, copy constructor and destructor are all required, and must be public, if the type is to be integrated into the meta-object system.
Suppose I have an object that needs to be built with some required parameters, because it has no sense to be built using the default constructor, for example:
struct IntPair
{
IntPair(int first, int second);
~IntPair();
};
To make it available in the Qt Meta Object system, as the doc states, it requires the default constructor. But practically, it has no sense to give the opportunity to build an IntPair object without a pair of integer numbers (sorry for the ugly example).
Is there a way to achieve this without implementing the default constructor? I'm thinking about a sort of friendship between my object and the Qt Meta Object system...
Basically, I cannot understand why the default constructor is needed.
There are two parts to the question:
Achieving a custom Meta Object without implementing a default ctor.
Understanding why a default ctor is required by Qt in this case.
Other respondents have addressed (2) already.
I wish to address (1).
I wrote a class, and I intend for users of this class to call a ctor I wrote which requires several arguments. However, because of the Qt-related requirements, I am forced to add a zero-argument constructor.
It would make me happy to at least make the zero-arg ctor private, so that I could enforce that all user code EXCEPT moc-generated "magic" code will be barred from using that ctor.
Hello, happiness! It is possible.
You can indeed use friendship to make the default ctor private and still use Qt Metatype.
It looks something like this:
class MyClass {
Q_GADGET
Q_PROPERTY(QString text READ text)
public:
MyClass(QString text, bool sometruth, int someint);
QString text() const { return text_; }
private:
// Works in my project using Qt 5.12. (see hints below if it fails for you)
friend struct QtMetaTypePrivate::QMetaTypeFunctionHelper<MyClass, true>;
// Prefer the ctor that takes arguments. This ctor only exists to satisfy Qt.
MyClass();
QString text_;
};
There are two ways you can solve the problem of figuring out WHAT to befriend.
You can mark the ctor private, try to recompile, and scrutinize the compiler error to figure out what other type is trying to access the ctor of your class.
Or, you can put an assert(false); in the body of your ctor, create a binary with debug symbols (including Qt debug symbols), then look at the stack in the debugger when the assertion fails. The stack will show the Qt-internal member-function or free function that called into your ctor. Friend whatever that caller is.
This last method (using the debugger) is what worked for me. (I wasn't fluent enough in compiler-ese to discern which type from the output of the gigantic compiler error was what I needed to add as my friend.)
It has to do with QVariant's (templated) implementation.
Look at qvariant.h in the QT5.5 source code tree, and you'll find this:
T t;
if (v.convert(vid, &t))
return t;
return T();
And also:
old->~T();
new (old) T(t); //call the copy constructor
Hence the need for a public constructor/desctructor, and copy-constructor.
The advantage of all of this is being able to use your custom type in signals/slots (and other meta-object magic), but there are drawbacks like in your situation. It's just a trade-off that you have to live with.
As a workaround, you could have some sort of "init()" method that actually initializes the object after it's constructed. Not as safe/elegant, but it works.
As to why, there's a design reason behind it. It involves a "Identity vs Value" discussion that I think is too long to paste here.
As to how, #AlexanderVX commented on using default values in arguments.
Custom data type should have public default constructors because many parts of the Qt framework will call it to avoid returning null pointers. E.g. QVariant and containers accessors (e.g. QHash::value()).
In your case IntPair() : IntPair(0,0) { } should be nice, isn't it ?
In many cases it is convenient to hold data in objects impementing Qt's implicit sharing pattern (see http://doc.qt.io/qt-5/implicit-sharing.html), in which case the default constructor may easily initialize with QSharedDataPointer(0) and every accessor return a default value when pointer is null (e.g. 0 for an int, QString() for a QString, etc.), guess what: every accessor will be able to provide a default value by calling the public default constructor of the data type because it is required to have one :-).
I have to do some changes in a project so I have to change some classes. This code was made by another person and I found a really weird problem doing my task (or at least trying until this wild mushroom appeared )
I have the next ClassA.cpp and I want to remove the m_ElemVar(enumType):
CClassA::CClassA(): m_iIntVariable(0), m_fFloatVar(0.0f), m_ElemVar(enumType1)
{
// more variables initizalized there
otherVariable = value;
...
}
the .h :
#include "CMyElement"
class CClassA
{
public:
CClassA();
virtual ~CClassA();
private:
CMyElement m_ElemVar; // THIS is the var
int m_iIntVariable;
float m_fFloatVar;
...
}
So the thing is that I don't want the m_ElemVar(enumType1) there because I will initialize it in another place, BUT if I remove it, when I build the class or the project it says:
error: no matching function for call to ‘CMyElemnt::CMyElemnt()
candidates are CMyElemnt::CMyElemnt(enumTypeName)
while if I remove the m_fFloarVar for example it doesn't complains.... That confuses me a lot because as you can see in the .h there is nothing declared so I understand that this constructor should not expect anything.
I've clean and build it again, and also searched into google but nothing found so any help would be very appreciated. Thank you so much
Looks like CMyElemnt does not have a parameterless constructor so you have to call one that takes the enum. Maybe you could reassign it later if you cannot change its interface.
The issue you are having is all objects of a class must be constructed in order for the class to be constructed. If you don't construct one of the member explicitly then the compiler will do it for you implicitly using the default constructor. Since CMyElemnt does not have a default constructor you will get an error. The reason not initializing m_fFloatVar works is it is a float and the compiler can default construct a float.
To look at a different way anything you can write as
some_type some_name;
Is default constructable. If you have do include parameters like:
some_type some_name(some_variables)
Then it is not default constructable and you need to initialize it yourself.
We use doxygen to document our classes. I would like to explicitly document that a class has generated constructors and/or destructors, to indicate that I've thought about it and decided that e.g. copying using the generated copy constructor is safe. However, the constructor/destructor is not declared and hence doxygen does not know to which function the documentation belongs. Are there ways to make doxygen include function comments even if the function is never declared?
//! The Foo class documentation
class Foo {
//! #fn Foo(const Foo&)
//! Generated copy constructor OK to use
//! method documentation
void method();
}
Also I wouldn't want to write the signature of the generated files at all.
I guess my other option is to just describe it in the class header. Are there any other approaches?
If you use the = default notion introduced in C++0x for your default generated constructors, doxygen should pick them up
http://www2.research.att.com/~bs/C++0xFAQ.html#default
I don't know if doxygen has implemented the C++0x new keywords and patterns yet though
While reading some stuff on the pImpl idiom I found something like this:
MyClass::MyClass() : pimpl_( new MyClassImp() )
First: What does it mean?
Second: What is the syntax?
Sorry for being such a noob.
This defines the constructor for MyClass.
The syntax is that of a constructor definition with an initialization list (I assume there is a set of braces following this that define the body of the constructor).
The member pimpl_ of MyClass is being initialized as a pointer to a new object of type MyClassImp. It's almost the same as the following:
MyClass::MyClass()
{
pimpl_ = new MyClassImp();
}
However, it is preferable to use the initialization list for initializing class members wherever possible; see the C++ FAQ Lite entry linked above.
It's an initialization list.
It allow you to set the values of member and base class constructor before the constructor code is called.
You should use it to initialize the values of your class instance.
In addition to being a constructor with an initialiser list as others have already explained, it's also using the private implementation pattern.
C++ requires the class declaration to include all the public and private members of the class. This can result in you having to expose implementation details that you don't want to, and to making your implementation part of your API/ABI. It can also significantly increase compile times due to additional #includes in the public headers to support the private member variables.
Making a second class with the actual implementation and just exposing the functional API makes this much cleaner, but at the cost of an additional layer of indirection.
C generally handles this by having a pointer to an opaque object which the library creates and destroys for you.