我应该声明这些方法为常量吗? 我正在研究一些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,则禁止此操作。如果将其设置为constconst
,则两者都允许
我想这是一个有利于使这个
常数的论点 如果侦听器存储为指针集合,则即使对象是常量,也可以对其调用非常量方法
如果约定是侦听器可以在收到通知时更新其状态,则该方法应为非常量
您的意思是侦听器可以回调对象并修改它。但是监听器本身不会改变,因此Notify调用可以是const,但是您将指向您自己对象的非const指针传递给它
如果侦听器已经具有该指针(它只侦听一个对象),那么您可以将这两个方法都设置为常量,因为对象被修改是一个副作用。正在发生的是:
A叫B
B修改A作为结果
因此,A调用B会间接导致其自身的修改,但不是对自身的直接修改
如果是这种情况,您的两个方法都可以而且可能应该是常量。如果您不能保证调用函数的对象在函数调用前后保持不变,通常应将其保留为非常量。想想看——您可以编写一个侦听器,在对象为非常量时插入它,然后使用此函数来破坏常量的正确性,因为您曾经在对象为非常量时访问过该对象。那是错误的
请注意,它们不会修改状态
这样他们就可以
从技术上讲,这是一种非常有效的方法,
即使它们通常会修改
整个系统的状态。在里面
特别是,侦听器对象可能
调用此对象并修改
它
由于侦听器可以更改状态,因此此方法不应为常量。从您所写的内容来看,听起来您使用了大量的const_cast和通过指针调用。const correction有一种(有意想要的)传播方式。您应该在任何可以使用const的地方使用它,而const_-cast和c-style-cast应该是处理客户机代码的工件-从来没有在您的代码中使用过,但很少有例外
如果void notifyfoodated()
调用监听器[all].onfoodated()
而ononfoodated()
不是常量,那么您应该明确限定此变异。如果您的代码在整个过程中都是常量正确的(我对此提出质疑),那么(通过方法声明/侦听器访问)明确表示您正在变异侦听器(成员),那么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);
};