有没有一种方法可以自定义编译错误/警告信息?

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
}

构建小部件(Widget)需要进行虚函数调用(这就是为什么我编写了 Widget::Init() 的原因)。是否有一种方法可以对 Widget::Init() 进行约束,使其在对象的任何使用之前必须被调用,并且如果用户违反约束,则引发错误?另一个问题是创建自定义警告消息以针对已弃用的方法。在上面的代码中,如果我的类的用户调用 Widget::paint(),如何告诉他们使用已弃用的 Widget::paint() 代替,并告知他们使用已弃用的方法的后果?谢谢。

3
如果用户无法构造任何Widget对象来调用该方法,那么用户如何调用Widget实例的Init()方法是没有意义的。 - user743382
1
问题的第二部分在这里得到回答C++标记为弃用 - Bo Persson
无论你认为做这件事的原因是什么,都不是一个好的理由。C++使用构造函数是因为将对象生命周期开始的时刻与获得有效值的时刻分离的概念是错误的来源。 - StoryTeller - Unslander Monica
@StoryTeller 如果我需要调用一个虚函数才能构造对象,我认为在构造函数内部调用它是一个不好的想法。 - DDMC
@LYF_HKN - (a) 这是不可能的。(b) 那么调用虚函数应该由另一个实体负责。 - StoryTeller - Unslander Monica
为什么应该让调用代码来完成它呢?在子类的构造函数中以非虚拟的方式调用该函数。 - StoryTeller - Unslander Monica
2个回答

2

问题的第一部分:

不,没有好的方法可以在使用私有方法时提供自定义消息。我建议的做法是确保您只有一个公共API,该API将请求转发到私有实现。这可以通过某些 Pimple 模式或创建一个 facade 来实现。

由于您没有指定获取 Widget 的方式,因此我目前假设这是一个 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();
    // ...
};

这样做的缺点是你需要编写一些/很多转发代码。

你问题的第二部分:

class Widget {
public:
  void Init();
  [[deprecated("use paintWidget instead")]] void Paint();
  void PaintWidget(); // A new implementation of paint
  ...
private:
  Widget();
  ...
}

请注意,如果您没有使用启用C++17的现代编译器的访问权限,则可能需要查看您的编译器特定属性。

非常抱歉之前问题表述不够清晰,我已经更新了问题,您能否检查一下并更新回答。谢谢。 - DDMC
所以,您删除了私有构造函数并使init-call成为虚函数。现在我更加困惑:s - JVApen
我又一次未能表达我的想法 :( 我想传达的是:一个对象在构造时需要调用虚函数,因此我创建了Init函数来构造对象(其中虚调用是安全的)。如何设置约束条件,以便在使用对象之前必须调用Init - DDMC
我现在认为我理解了这个问题,但是我仍然困惑于为什么你需要Init方法,因为每个继承类都可以在其构造函数中编写此初始化功能。 - JVApen

1
你可以使用#warning指令,大多数常用的编译器(如GCC、VC、Intel和Mac)都支持#warning消息。
#warning "this is deprecated, use the Init() method instead"

一个好的实践是不仅显示警告(人们可以忽略),而且使用#error指令使编译失败(这是相当标准的):
#  error "this method is forbidden and private"

作为 Visual Studio 特有的 solution,您可以使用 pragma

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接