未实例化方法的默认空用法 class
Default empty usage of methods of uninstantiated class
在我的系统中,我有许多回调,其中包含调用 classes 的方法,这些回调未根据某些配置值实例化,当它们未初始化时,我希望调用它们时不执行任何操作,而不是引发段错误。
例如我有一些 InitManager class 在它的构造函数中我们有:
if (config.is_connected) { std::shared<CloudClient> cloud_client = std::make_shared<CLoudCLient>(); }
并且在 InitManager 中我有一个来自另一个进程的一些事件的回调,其中包括以下内容:
...
cloud_client->saveData();
...
cloud_client->notifyUser();
...
所以我目前的解决方案是在使用每种方法之前:
...
if (cloud_client) {
cloud_client->saveData();
}
...
if (cloud_client) {
cloud_client->notifyUser();
}
...
它保留了我想要的行为。问题是,每当另一个开发人员添加新方法或使用旧方法时,他可能不会检查 cloud_client 是否存在,而我们只能在检查该特定配置时通过测试来弄清楚。此外,我的解决方案使代码更难阅读,因为它包含许多 if 条件。
如果有人有一些设计解决方案可以让我做到:
cloud_client->notifyUser();
每次都没有if条件,当云客户端不存在时什么也不做。如果开发人员没有使用
,甚至只是使每个 class 方法的使用都在编译中失败
`if (cloud_client)`
会很棒的!
谢谢你,OP,编辑你的问题。你做的很好,问题已经清楚了。
我建议 'wrapper' class 用于 CloudClient
- 我们称它为 CloudClientWrapper
,它包含指向 CloudClient
实例的指针(可能be nullptr
) 作为成员变量。 CloudClientWrapper
然后可以负责测试那个变量是否是 nullptr
,这意味着调用者不需要担心它。
为了防止外部代码直接调用 CloudClient
方法,声明它们 private
并使 CloudClientWrapper
成为 CloudClient
的 friend
。
所以,像这样:
class CloudClient
{
friend class CloudClientWrapper;
private:
void Foo ();
void Bar ();
// ...
};
class CloudClientWrapper
{
public:
CloudClientWrapper (CloudClient *client) : m_client (client) { }
void Foo () { if (m_client) m_client->Foo (); }
void Bar () { if (m_client) m_client->Bar (); }
// ....
private:
CloudClient *m_client;
};
当然,您的方法可以采用参数并具有 return 类型。 CouldClientWrapper
只需要传递它们。可能有很多样板文件,但我没有找到更好的方法。
顺便说一下,完全在头文件中实现 CloudClientWrapper
可能会有一些性能优势。它使编译器可以轻松地内联代码。有 link 时间优化 (LTO) 这样的东西,它旨在做同样的事情,但根据我的经验,它会减慢 link 时间并生成一堆巨大的中间构建产品(我已经放弃了)。
在我的系统中,我有许多回调,其中包含调用 classes 的方法,这些回调未根据某些配置值实例化,当它们未初始化时,我希望调用它们时不执行任何操作,而不是引发段错误。 例如我有一些 InitManager class 在它的构造函数中我们有:
if (config.is_connected) { std::shared<CloudClient> cloud_client = std::make_shared<CLoudCLient>(); }
并且在 InitManager 中我有一个来自另一个进程的一些事件的回调,其中包括以下内容:
...
cloud_client->saveData();
...
cloud_client->notifyUser();
...
所以我目前的解决方案是在使用每种方法之前:
...
if (cloud_client) {
cloud_client->saveData();
}
...
if (cloud_client) {
cloud_client->notifyUser();
}
...
它保留了我想要的行为。问题是,每当另一个开发人员添加新方法或使用旧方法时,他可能不会检查 cloud_client 是否存在,而我们只能在检查该特定配置时通过测试来弄清楚。此外,我的解决方案使代码更难阅读,因为它包含许多 if 条件。 如果有人有一些设计解决方案可以让我做到:
cloud_client->notifyUser();
每次都没有if条件,当云客户端不存在时什么也不做。如果开发人员没有使用
,甚至只是使每个 class 方法的使用都在编译中失败 `if (cloud_client)`
会很棒的!
谢谢你,OP,编辑你的问题。你做的很好,问题已经清楚了。
我建议 'wrapper' class 用于 CloudClient
- 我们称它为 CloudClientWrapper
,它包含指向 CloudClient
实例的指针(可能be nullptr
) 作为成员变量。 CloudClientWrapper
然后可以负责测试那个变量是否是 nullptr
,这意味着调用者不需要担心它。
为了防止外部代码直接调用 CloudClient
方法,声明它们 private
并使 CloudClientWrapper
成为 CloudClient
的 friend
。
所以,像这样:
class CloudClient
{
friend class CloudClientWrapper;
private:
void Foo ();
void Bar ();
// ...
};
class CloudClientWrapper
{
public:
CloudClientWrapper (CloudClient *client) : m_client (client) { }
void Foo () { if (m_client) m_client->Foo (); }
void Bar () { if (m_client) m_client->Bar (); }
// ....
private:
CloudClient *m_client;
};
当然,您的方法可以采用参数并具有 return 类型。 CouldClientWrapper
只需要传递它们。可能有很多样板文件,但我没有找到更好的方法。
顺便说一下,完全在头文件中实现 CloudClientWrapper
可能会有一些性能优势。它使编译器可以轻松地内联代码。有 link 时间优化 (LTO) 这样的东西,它旨在做同样的事情,但根据我的经验,它会减慢 link 时间并生成一堆巨大的中间构建产品(我已经放弃了)。