我应该声明这些方法为常量吗? 我正在研究一些C++代码,其中有几个管理器对象,它们有私有的方法,例如< /P> void NotifyFooUpdated();

我应该声明这些方法为常量吗? 我正在研究一些C++代码,其中有几个管理器对象,它们有私有的方法,例如< /P> void NotifyFooUpdated();,c++,constants,static-code-analysis,const-method,C++,Constants,Static Code Analysis,Const Method,调用此对象的侦听器上的onfoodated()方法 请注意,它们不会修改此对象的状态,因此从技术上讲,它们可以成为const方法,即使它们通常会修改整个系统的状态。特别是,侦听器对象可能会回调该对象并对其进行修改 就个人而言,我想让它们保持原样,而不是声明它们const 但是,我们的静态代码检查器QAC将此标记为偏差,因此我要么必须声明它们为常量,要么必须说明它们为什么应该保持非常量并获得偏差许可 不声明这些方法的参数是什么 或者我应该遵循QAC并声明它们const? 我是否应该采用严格局限于这

调用此对象的侦听器上的
onfoodated()
方法

请注意,它们不会修改此对象的状态,因此从技术上讲,它们可以成为
const
方法,即使它们通常会修改整个系统的状态。特别是,侦听器对象可能会回调该对象并对其进行修改

就个人而言,我想让它们保持原样,而不是声明它们
const

但是,我们的静态代码检查器QAC将此标记为偏差,因此我要么必须声明它们为常量,要么必须说明它们为什么应该保持非常量并获得偏差许可

不声明这些方法的参数是什么 或者我应该遵循QAC并声明它们
const


我是否应该采用严格局限于这个对象的局部观点,或者考虑整个系统?< /P> < P>我猜您是在跟随HICPP或类似的东西。 我们要做的是,如果我们的代码违反了QACPP,并且我们认为它是错误的,那么我们就通过Doxygen(通过addtogroup命令,这样您就可以很容易地得到它们的列表)来记录它,给出违反它的原因,然后通过
//PRQA
命令禁用警告

不声明这些方法的参数是什么 或者我应该遵循QAC并声明它们
const

我是否应该采用严格局限于这个对象的局部观点,或者把系统看作一个整体?

您所知道的是,此调用的管理器对象“请勿更改”。然后管理器调用函数的对象可能会更改,也可能不会更改。你不知道

根据您的描述,我可以设想这样一种设计,其中所有涉及的对象都是
const
(通知可以通过将它们写入控制台来处理)。如果不将此函数设置为const,则禁止此操作。如果将其设置为const
const
,则两者都允许


我想这是一个有利于使这个
常数
的论点

如果侦听器存储为指针集合,则即使对象是常量,也可以对其调用非常量方法

如果约定是侦听器可以在收到通知时更新其状态,则该方法应为非常量

您的意思是侦听器可以回调对象并修改它。但是监听器本身不会改变,因此Notify调用可以是const,但是您将指向您自己对象的非const指针传递给它

如果侦听器已经具有该指针(它只侦听一个对象),那么您可以将这两个方法都设置为常量,因为对象被修改是一个副作用。正在发生的是:

A叫B B修改A作为结果

因此,A调用B会间接导致其自身的修改,但不是对自身的直接修改


如果是这种情况,您的两个方法都可以而且可能应该是常量。

如果您不能保证调用函数的对象在函数调用前后保持不变,通常应将其保留为非常量。想想看——您可以编写一个侦听器,在对象为非常量时插入它,然后使用此函数来破坏常量的正确性,因为您曾经在对象为非常量时访问过该对象。那是错误的

请注意,它们不会修改状态 这样他们就可以 从技术上讲,这是一种非常有效的方法, 即使它们通常会修改 整个系统的状态。在里面 特别是,侦听器对象可能 调用此对象并修改 它

由于侦听器可以更改状态,因此此方法不应为常量。从您所写的内容来看,听起来您使用了大量的const_cast和通过指针调用。

const correction有一种(有意想要的)传播方式。您应该在任何可以使用const的地方使用它,而const_-cast和c-style-cast应该是处理客户机代码的工件-从来没有在您的代码中使用过,但很少有例外


如果
void notifyfoodated()
调用
监听器[all].onfoodated()
而on
onfoodated()
不是常量,那么您应该明确限定此变异。如果您的代码在整个过程中都是常量正确的(我对此提出质疑),那么(通过方法声明/侦听器访问)明确表示您正在变异侦听器(成员),那么
notifyfoodupdated()
应符合非常量的条件。因此,您只需声明变异尽可能靠近源,它应该检查出来,常量正确性将正确传播。

使虚拟函数常量始终是一个困难的决定。让它们成为非常量是一条简单的出路。侦听器函数在许多情况下都应该是常量:如果它不改变侦听方面(对于此对象)。 如果侦听事件会导致侦听方注销自身(一般情况下),则此函数应为非常量


尽管对象的内部状态可能会在OnFooChanged调用时更改,但在接口级别,下次调用OnFooChanged时,将产生类似的结果。这使得它是常量。

在类中使用常量时,您可以帮助该类的用户了解该类将如何与数据交互。你在签合同。当您有一个对const对象的引用时,您知道对该对象的任何调用都不会改变其状态。该引用的常量仍然只是与调用方的约定。对象仍然可以在后台使用可变变量自由执行一些非常量操作。这在缓存信息时特别有用

例如,您可以使用以下方法创建类:

int expensiveOperation() const
{
    if (!mPerformedFetch)
    {
        mValueCache = fetchExpensiveValue();
        mPerformedFetch = true;
    }
    return mValueCache;
}
此方法可能需要很长时间才能执行
class X
{
public:
    int expensiveOperation() const;
private:
    int fetchExpensiveValue() const;

    mutable bool mPerformedFetch;
    mutable int mValueCache;
};
list<Observer> someManager;

void NotifyFooUpdated(const list<Observer>& manager) { ... }
class Args
{
};

class NotificationManager
{
private:
    class NotifyEntry
    {
    private:
        std::list<Delegate> m_Delegates;

    public:
        NotifyEntry(){};
        void raise(const Args& _args) const
        {
            for(std::list<Delegate>::const_iterator cit(m_Delegates.begin());
                cit != m_Delegates.end();
                ++cit)
                (*cit)(_args);
        };

        NotifyEntry& operator += (Delegate _delegate) {m_Delegates.push_back(_delegate); return(*this); };
    }; // eo class NotifyEntry

    std::map<std::string, NotifyEntry*> m_Entries;

public:
    // ctor, dtor, etc....

    // methods
    void register(const std::string& _name);     // register a notification ...
    void unRegister(const std::string& _name);   // unregister it ...

    // Notify interested parties
    void notify(const std::string& _name, const Args& _args) const
    {
        std::map<std::string, NotifyEntry*>::const_iterator cit = m_Entries.find(_name);
        if(cit != m_Entries.end())
           cit.second->raise(_args);
    }; // eo notify

    // Tell the manager we're interested in an event
    void listenFor(const std::string& _name, Delegate _delegate)
    {
        std::map<std::string, NotifyEntry*>::const_iterator cit = m_Entries.find(_name);
        if(cit != m_Entries.end())
            (*cit.second) += _delegate;
    }; // eo listenFor
}; // eo class NotifyManager
MyManager::MyManager()
{
    NotificationMananger.getSingleton().register("OnABCUpdated");
    NotificationMananger.getSingleton().register("OnXYZUpdated");
};


AnotherManager::AnotherManager()
{
    NotificationManager.getSingleton().register("TheFoxIsInTheHenHouse");
};
MyManager::someFunction()
{
    CustomArgs args; // custom arguments derived from Args
    NotificationManager::getSingleton().notify("OnABCUpdated", args);
};