4

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.

DDMC
  • 396
  • 2
  • 11
  • 3
    This doesn't make sense. How could a user call `Init()` of a `Widget` instance, if the user cannot construct any `Widget` to call that method on? –  Jan 15 '17 at 12:42
  • 1
    The second part of the question is answered here [C++ Mark as deprecated](http://stackoverflow.com/questions/295120/c-mark-as-deprecated) – Bo Persson Jan 15 '17 at 12:43
  • Whatever reason you think you have for doing this, it's not a good reason. C++ uses constructors because the notion of separating the moment an objects lifetime begins from the moment it obtains a valid value is a source of bugs. – StoryTeller - Unslander Monica Jan 15 '17 at 13:05
  • @StoryTeller If I need to call a virtual function in order to construct the object, I think it would be a bad idea calling it inside the constructor. – DDMC Jan 15 '17 at 13:07
  • @LYF_HKN - (a) It would be impossible (b) Then calling the virtual function should be the responsibility of another entity. – StoryTeller - Unslander Monica Jan 15 '17 at 13:08
  • (c) Why should the calling code be tasked with it? Have a child class call the function from within its own constructor in a non virtual manner. – StoryTeller - Unslander Monica Jan 15 '17 at 13:10

2 Answers2

2

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.

Sebastian Brosch
  • 42,106
  • 15
  • 72
  • 87
JVApen
  • 11,008
  • 5
  • 31
  • 67
  • I'm sorry for not being clear in the question, I've update the question, can you check it and update this answer. Thanks. – DDMC Jan 15 '17 at 13:05
  • So, you removed the private Ctor and the made the init-call virtual. Now I'm even more confused :s – JVApen Jan 15 '17 at 13:07
  • I failed again to express my idea :( What I want to convey is: An object need to call a virtual function when constructing, so I create the `Init` function to construct the object (in which the virtual call is safe). How can I make a constraint so that `Init` must be called before any use of the object? – DDMC Jan 15 '17 at 13:18
  • I think I understand the question now, though, I'm still confused on why you need the Init-method while each inheritting class can write this init-functionality in its Ctor. – JVApen Jan 15 '17 at 13:28
1

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.

Community
  • 1
  • 1
fatihk
  • 7,789
  • 1
  • 26
  • 48