Search code examples
c++c++11wxwidgets

What's the difference between an object created in function call and object passed in


This is obviously a hole in my self taught computer science education...

The constructor for a text control (wxTextCtrl) in a wxWidgets application has an optional parameter for a validator object. All of the code examples create the validator on the fly within the constructor for the text control.

This works..

wxString value = L"0.0";
wxTextCtrl* _Text = new wxTextCtrl(this, wxID_ANY, value, 
    wxDefaultPosition, wxDefaultSize, 0, 
    wxTextValidator(wxFILTER_NUMERIC, &value));

However in my particular case I want to create the validator in another function and pass it back, which isn't working. As an intermediate step I've tried to create it just before creating the wxTextCtrl and pass it in but that doesn't work either...

wxString value = L"0.0";
wxValidator valid = wxTextValidator(wxFILTER_NUMERIC, &value);
wxTextCtrl* _Text = new wxTextCtrl(this, wxID_ANY, value, 
    wxDefaultPosition, wxDefaultSize, 0, valid);

Although this compiles and runs it doesn't perform the validation. Can anyone explain why?

The prototype for the wxTextValidator calls for a constant reference..

wxTextCtrl::wxTextCtrl  (   wxWindow *  parent,
    wxWindowID  id,
    const wxString &    value = wxEmptyString,
    const wxPoint &     pos = wxDefaultPosition,
    const wxSize &  size = wxDefaultSize,
    long    style = 0,
    const wxValidator &     validator = wxDefaultValidator,
    const wxString &    name = wxTextCtrlNameStr 
)

Solution

  • You have sliced the wxTextValidator object when you assigned it to a variable of type wxValidator, its base class. To fix this, you'll need to preserve the more specific type:

    wxTextValidator valid = wxTextValidator(wxFILTER_NUMERIC, &value);
    

    You can use auto to avoid repeating yourself.

    Alternatively, you can use lifetime extension which occurs when assigning a temporary to a const reference:

    const wxValidator& valid = wxTextValidator(wxFILTER_NUMERIC, &value);
    

    This works because there is no copy, and therefore no slicing.

    Note that when designing your own classes, it's often a good idea to prevent object slicing by making your base classes abstract, or making their (copy) constructors protected.