C++ 有没有办法自定义编译错误/警告消息?

C++ 有没有办法自定义编译错误/警告消息?,c++,C++,例如,如果我有这样一个类: 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 ne

例如,如果我有这样一个类:

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
}
构建
小部件
需要一个虚拟函数调用(这就是为什么我编写了
小部件::Init()
)。有没有一种方法可以对
Widget::Init()
进行约束,以便在使用对象之前必须调用该约束,并且如果用户违反该约束,则会引发错误?另一个问题是为不推荐使用的方法创建自定义警告消息。使用上面的代码,如果我的类的用户调用
Widget::paint()
,我如何告诉他们使用
Widget::paintWidget()
而不是弃用的
Widget::paint()
,并告诉他们使用弃用的Widget::paint()的后果?谢谢。

您可以使用#warning指令,大多数广泛使用的编译器(GCC、VC、Intels和Mac)都支持#警告消息

#warning "this is deprecated, use the Init() method instead"
一种很好的做法是,不仅要显示警告(人们可以忽略),还要使用#error指令(相当标准)使编译失败:

作为Visual Studio的专用工具,您可以使用pragma。

问题的第一部分: 不,在使用私有方法时没有提供自定义消息的好方法。我要做的是确保您只拥有一个转发到私有实现的公共API。这可以通过一些粉刺图案或通过创建外观来实现

由于您没有指定用户获取小部件的方式,因此我目前假设为单例

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();
    // ...
};
这样做的缺点是您必须编写一些/大量的转发代码

你问题的第二部分:
请注意,如果您无法访问启用了C++17的现代编译器,则可能需要检查编译器特定的属性。

这没有意义。如果用户不能构造任何
小部件
来调用该方法,那么用户如何调用
小部件
实例的
Init()
?这里回答了问题的第二部分,无论您认为这样做的原因是什么,这都不是一个好的理由。C++使用构造函数,因为从对象获得有效值的时刻分离对象生命周期的概念是错误的来源。@ StutyTeLeLee如果要构建对象,需要调用虚函数,我认为调用构造函数里面的想法是不好的。@ LyfyHKN-A(a)是不可能的(b)那么调用虚拟函数应该是另一个实体的责任。很抱歉,问题不清楚,我已经更新了问题,你能检查一下并更新这个答案吗。谢谢。所以,您删除了私有Ctor,并使初始化调用虚拟化。现在我更困惑了:sI再次未能表达我的想法:(我想传达的是:一个对象在构造时需要调用一个虚拟函数,所以我创建了
Init
函数来构造该对象(其中虚拟调用是安全的)。我如何设置约束,以便在使用对象之前必须调用
Init
?我想我现在理解了这个问题,但是,我仍然不明白为什么需要Init方法,而每个继承类都可以在其构造函数中编写此Init功能。
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();
  ...
}