For example, if I have a class like this:
class Widget {
public:
virtual void Init(); // In this function, call some virtual function
// to construct the object
void Paint(); // Deprecated, use paintWidget instead
void PaintWidget(); // A new implementation of paint
... // Other stuff, including a virtual function
// which need to be called to construct the object
}
The construction of a Widget requires a virtual function call (that's why I wrote the Widget::Init()). Is there a way to make a constraint on Widget::Init() so that it must be called before any use of the object, and raise error if the user violates the constraint? Another problem is creating a customize warning message for a deprecated method. With the code above, if a user of my class calls Widget::paint(), how can I tell them to use Widget::paintWidget() instead of deprecated Widget::paint(), and tell them about the consequence of using the deprecated one? Thank you.
Part 1 of your question:
No, there is no good way of giving a custom message on using a private method. What I would do is to make sure that you only have a public API which forwards to the private implementation. This can be done via some pimple pattern or by creating a facade.
As you did not specify the way someone would get the Widget, I'm currently assuming a Singleton.
class Widget {
public:
Widget() : _impl(getHoldOfPrivateWidgetViaSingleton())
{
_impl.init();
}
// ...
private:
PrivateWidget &_impl;
};
// Note: rename of the Widget in your example
class PrivateWidget {
private:
friend class Widget;
PrivateWidget();
// ...
};
The disadvantage of doing this is that you will have to write some/a lot of forwarding code.
Part 2 of your question:
class Widget {
public:
void Init();
[[deprecated("use paintWidget instead")]] void Paint();
void PaintWidget(); // A new implementation of paint
...
private:
Widget();
...
}
Note that if you don't have access to a modern compiler with C++17 enabled, you might want to check out your compiler specific attributes.
You can use #warning directive, most of the widespread compilers (GCC, VC, Intels and Mac), support #warning message.
#warning "this is deprecated, use the Init() method instead"
A good practive is to not only show a warning (which people can ignore), but make the compiling fail, using the #error directive (which is quite standard):
# error "this method is forbidden and private"
As a Visual Studio specific solution, you can use pragma.
Related
I am currently implementing a small soft, I want this soft work on Mac OS and Window OS, so I want use GLFW for Mac environment and Window API for Windows environment (I know GLFW is cross platform but that's not the point..)
My problem is a design implementation problem:
I have created a windowManager class that keeps an instance of a Window class. This Window keeps an instance of an object that is a PatternWindow, where PatternWindow is an interface. I have an object PatternGLFW3_VULKAN that implements PatternWindow. This PatternGLFW3_VULKAN has a member GLFWwindow * _window, and PatternGLFW3_VULKAN initializes _window with glfwCreateWindow(...).
class Window : public Singleton<Window>
{
public:
somefunction(...)
initializePatternWindow(unique_ptr<PatternWindow>&& patternWindow)
unique_ptr<PatternWindow> getPatternWindow(){return _patternWindow;}
private:
unique_ptr<PatternWindow> _patternWindow;
}
class PatternWindow
{
public:
PatternWindow();
virtual ~PatternWindow();
virtual void initialize() = 0;
virtual void destroy () = 0;
};
class PatternGLFW3_VULKAN : public PatternWindow
{
public:
PatternGLFW3_VULKAN ();
~PatternGLFW3_VULKAN();
virtual void initialize();
virtual void destroy();
const GLFWwindow& getWindow() const {return *_window;}
private:
GLFWwindow * _window;
};
My question is about the getWindow() function in my PatternGLFW3_VULKAN class; how I can create a virtual getWindow() function in my PatternWindow class in order to get my GLFWwindow* window of the PatternGLFW3_VULKAN at run time. If I am on Mac OS environment, I can create a virtual function GLFWwindow& getWindow() in my PatternWindow, but if I run my software in a Window environment, the type GLFWwindow of the virtual function getWindow() of the patternWindow class won't be correct...
How can I do in order to have a virtual getWindow() in PatternWindow my that returns GLFWwindow or a instance the Windows API screen at run time ?
EDIT:
class PatternWindow
{
public:
PatternWindow();
virtual ~PatternWindow();
virtual void initialize() = 0;
virtual void destroy () = 0;
virtual /*UNKNOW TYPE AT THE COMPILATION*/ getWindow() = 0;
};
/*UNKNOW TYPE AT THE COMPILATION*/
is my problem I do not know how to deal with it, for getting a GLFWwindow* when i am in Mac OS and Windows instance for the windows API when I am compiling in the Windows environment..
In the main loop of my software in want something like that
int main(int argc, char** argv)
{
//initialisation of all my managers ans the data ect..
while(!WindowClosed(Window::getPatternWindow()->getWindow()))
{
//DO SOME STUFF
}
}
The pattern you are heading towards can be done, but you might regret it later. I would infer from your setup that you have two overloads of WindowClosed() – one whose parameter is a GLFWwindow, and one whose parameter is a WinAPI type. The former would use GLFW methods to detect if the window is closed, while the latter would use the Windows API. One problem is that one of organization: how many files contain GLFW-specific methods? Maybe you even have a file with both GLFW methods and Win API methods? That's not necessarily wrong, but it could be a pain in the long run. Another problem is that this approach diverges from the traditional object-oriented approach.
Still, let's not force you down one path through lack of knowledge. To make this approach work, you could use the preprocessor and a typedef. If compiling for Mac, you would use a line like typedef PatternGLFW3_VULKAN WindowType;. If compiling for Windows, you'd use a line defining WindowType to be the corresponding Windows type. Choosing between these lines would be accomplished via #ifdef WINDOWS (or whatever condition is most appropriate). Then getWindow() could be declared to return WindowType.
A better approach (which you realized in the comments) is to shift the functionality to the window objects. Instead of function(object), use object.function(). This requires more virtual functions in your interface class, but there is a benefit that you have fewer files that are OS-specific.
class PatternWindow
{
public:
PatternWindow();
virtual ~PatternWindow();
virtual void initialize() = 0;
virtual void destroy () = 0;
virtual bool closed () = 0; // <-- New pure virtual function
};
class PatternGLFW3_VULKAN : public PatternWindow
{
public:
PatternGLFW3_VULKAN ();
~PatternGLFW3_VULKAN();
virtual void initialize();
virtual void destroy();
virtual bool closed(); // <-- OS-specific code is no longer in an extra file
private:
GLFWwindow * _window;
};
Then in your main function, the call would be:
while(!Window::getPatternWindow()->closed())
There is a further step you might consider. (The question appropriately does not have enough details to determine if this is a viable option.) You might not need polymorphism for what you are trying to do. Suppose you were to use the following declaration.
class PatternWindow
{
#ifdef WINDOWS // Or whatever test is appropriate
typedef PatternGLFW3_VULKAN * WindowType;
#else
typedef /* Windows API type */ WindowType;
#endif
public:
PatternWindow();
~PatternWindow();
void initialize();
void destroy ();
bool closed ();
private:
WindowType _window;
};
This interface no longer supports polymorphism. Is that a bad thing? Do you need multiple classes derived from PatternWindow under a single operating system? Perhaps not. Here is a potential implementation file for this class.
#include "PatternWindow.h"
#ifdef WINDOWS // Or whatever test is appropriate
#include "PatternWinAPI.src" // <-- File with an implementation based on Win API
#else
#include "PatternGLFW.src" // <-- File with an implementation based on GLFW
#endif
If you don't like the .src extension, use something else. Just don't make those files look like something to be compiled on their own. Each file would have an implementation appropriate for the API it uses. For example, PatternGLFW.src might contain a function definition like the following.
void PatternWindow::initialize()
{
_window = glfwCreateWindow(...);
// Etc.
}
This eliminates the overhead of polymorphism and does not seem to introduce a coding burden. Also, you don't have to keep track of which files are needed for which operating systems (simpler build setup). The organization of PatternWindow.cpp is uncommon, though.
I need to connect a QPushButton (startListeningPushButton) from my StartWindow to a slot in my MainController. I still have a few questions:
Should I make a pointer of Ui::startWidget ui, because by default Qt created it as a normal variable?
Is getStartWindow() the right way to get the StartWindow from ViewController?
What would be the right way to get startListeningPushButton from StartWindow (is my getter right)?
This is my code:
MainController.cpp:
MainController::MainController()
{
connect(m_viewController.getStartWindow()->getStartListeningPushButton, &QPushButton::clicked, this, &MainController::bla)
}
ViewController.cpp:
StartWindow* ViewController::getStartWindow()
{
return &startWindow;
}
StartWindow.cpp:
QPushButton* StartWindow::getStartListeningPushButton()
{
return ui->fStartListeningPushButton;
}
StartWindow.h:
#ifndef STARTWINDOW_H
#define STARTWINDOW_H
#include "ui_startwindow.h"
class StartWindow : public QWidget
{
Q_OBJECT
public:
StartWindow(QWidget *parent = 0);
~StartWindow();
QPushButton* getStartListeningPushButton();
private:
Ui::startWidget *ui;
};
#endif // STARTWINDOW_H
If you are using Qt Designer and Qt IDE generated such code that it's object not a pointer I don't think that you should make it pointer.
Yeah, returning a pointer to QWidget (StartWindow in your case) is pretty OK.
Your getter is OK.
Seems like you have mistype in your connect, it should look like this:
QObject::connect(m_viewController.getStartWindow()->getStartListeningPushButton(), SIGNAL(clicked()),
this, SLOT(bla()));
It's unclear if you have and then what is your problem.
The only thing I doubt would work is the first parameter of your call to connect:
m_viewController.getStartWindow()->getStartListeningPushButton should actually be m_viewController.getStartWindow()->getStartListeningPushButton() (to have the function be called so that you get the pointer to expected QPushButton and pass it to the connect function).
In the connect function:
First and third parameter must be of type QObject*. So this can either be this pointer (if current class is derived from QObject), or any class attribute of type QObject* (ui->fStartListeningPushButton) or a function call returning QObject* (m_viewController.getStartWindow()->getStartListeningPushButton()). But m_viewController.getStartWindow()->getStartListeningPushButton (with no ()) does not make sense here).
Second parameter must be a signal (declared in header file class using signals: keyword. You don't need implement any code here, you just declare the signal and Qt MOC mechanism implements it silently). Valid syntax for this parameter is &QPushButton::clicked or SIGNAL(clicked()) (Qt4 syntax, still valid in Qt5).
Fourth parameter must be a slot (declared in header file class using slots: keyword, and implemented by you). Valid syntax for this parameter is &MainController::bla or SLOT(bla()) (Qt4 syntax, still valid in Qt5).
There's actually a fifth optional parameter to use when you'll start dealing with threads.
I was just playing around with the "state design pattern" and had a couple of questions on how exactly errors are handled in a state machine. Let us take the case below
class state_machine
{
private:
state state1;
state state2;
public:
}
class state
{
private:
state_machine* m_state_machine; /** Will pass the pointer to states **/
public:
void perform_state1_action();
void perform_state2_action();
}
class state1: public state
{
public:
void perform_state1_action()
{
/**
Functionality
**/
}
void perform_state2_action(); // Have nothing to do for this function
}
class state2: public state
{
public:
void perform_state2_action()
{
/**
Functionality
**/
}
void perform_state1_action(); // Have nothing to do for this function
}
My question is how do I gracefully handle the case where we call perform_state2_action when its in state1. Do I write a base function implementation with nothing or maybe error logging functionality?
This design pattern requires you to provide public methods that are available for every state. If you come across a situation that you feel an urge to add an action that is valid only for one of them, it could mean one of the following:
You should make it private and call it from more general, public method(s), which can be implemented for all of your states
This method should be moved outside of the state machine because it is not related to the state
This is a specific case where empty implementation is a correct behaviour (so no error log needed)
You have chosen wrong design pattern
I decided to use the state design pattern with minor changes:
Use a generic name for a function like "do_task" and use this to call the needed private functions.
This provided the benefits of the state design pattern at the same time preventing creation of surplus absolute virtual functions
Im implementing a new slot which just has to call the method reset(). My new class is subclassing QAbstractListModel in which QAbstractListModel::reset() exists.
//stationlist.h
class StationListModel : public QAbstractListModel
{
Q_OBJECT
...
public slots:
void dataChanged();
//stationlist.cpp
...
void StationListModel::dataChanged()
{
reset();
}
However, in the implementation the method reset() is recognized as QTextStream::reset() and doesn't compile because of this. What could be the cause for such behaviour?
Thanks to the comment, the conclusion is that the method QAbstractListModel::reset() doesn't exist.
It is here only still available fer backwards compatibility http://qt-project.org/doc/qt-5.1/qtcore/qabstractitemmodel-compat.html#reset.
I believe that QTextStream::reset() is just something that the QtCreator offered as a global autocomplete.
The solution is to use non deprecated method.
I was working for a while with different C++ GUI frameworks (e.g. Qt, wxWidgets, also some proprietary) but cannot decide for myself regarding the topic described below.
As discussed in several questions/answers here, direct use of delete this is valid in C++ (as long as you don't dereference this any more), but it is in most cases not good idea.
But in some cases, object invokes its destructor indirectly. This situation specifically often arise in event drive systems (GUI applications come to mind first).
class Kernel {
public:
void Start() {
_window = new Window();
}
void OnCloseButton() {
if (_window) {
_window->Close();
delete _window;
_window = NULL;
}
private:
MyWindow * _window;
};
class MyWindow
{
public:
MyWindow(Kernel & kernel) : _kernel(&kernel) {
Connect(my_button_close_event, this, OnCloseButtonClicked);
}
OnCloseButtonClicked() {
// This call actually calls destructor of this object.
_kernel->OnCloseButton();
// If we access any fields of Window here, we're going to have problems
}
private:
Kernel * _kernel;
};
Notice: I did not try to compile the code - it may have typos or bad practices. But it should illustrate the idea.
So, the question is: Is it OK to do something like in the example above: the handler of the event calls some other function (method of its owner), which indirectly deletes this?
Or should I better make the Kernel class event aware and connect the event from the button directly to the method in the Kernel and then we do not have this situation of indirect call to delete this.
Thanks in advance.
It's possible to do so since the Window instance is created by the Start() method but it's a bad practice in Object Oriented Programming.