- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
有人可以描述作者 John Lakos 在以下引用中提到的精确编码策略吗?
约翰·拉科斯:
More controversially, it is often better to have two copies of a struct—e.g., one nested/private in the .h file (accessible to inline methods and friends) and the other at file scope in the .cpp file (accessible to file-scope static functions) —and make sure to keep them in sync locally than to pollute the global space with an implementation detail.
引用出现在较新的 Lakos 大部头,Large Scale C++ .
(这本书是对与 Lakos 早期著作相同主题的更新处理,Large Scale C++ Software Design)
引用在第 9 页的第 0.2 节中。
如果后面的章节清楚 Lakos 描述的内容,我会返回这里并发布答案。
与此同时,我对理解这句话着迷了,我试图浏览本书的目录和索引以寻找更多线索,但尚未找到答案。
下面是我自己的示例代码,我想象会用神秘的策略解决这个问题:
// THE HEADER
namespace project
{
class OuterComponent
{
public:
inline int GetFoo()
{
return m_inner.foo;
}
int GetBar();
private:
struct InnerComponent
{
int foo = 0;
int bar = 0;
};
InnerComponent m_inner;
};
} // namespace project
连同:
// THE CPP IMPLEMENTATION FILE
namespace project
{
namespace
{
/*
MYSTERY:
Per the book quotation, I can somehow add a "copy of InnerComponent" here?
And "make sure to keep them in sync locally"?
*/
// COMPILATION ERROR (see below)
int FileScopeComputation( OuterComponent::InnerComponent i )
{
return i.bar - 3;
}
} // namespace
int OuterComponent::GetBar()
{
return FileScopeComputation( m_inner );
}
} // namespace project
当然,上面的不会编译。
错误将类似于:
error: ‘struct project::OuterComponent::InnerComponent’ is private within this context
int FileScopeComputation( OuterComponent::InnerComponent i )
^~~~~~~~~~~~~~
名为 FileScopeComputation
的自由函数无法访问 InnerComponent
,原因我很清楚。
将上述代码与书名联系起来
回到 Lakos 的引述,我的想法是 FileScopeComputation
是引述所称的 “文件范围静态函数” 的一个实例。
使代码编译的一个“明显”解决方案是移动 InnerComponent
,以便它在 OuterComponent
的 public
部分中声明。
但是,我认为我的“显而易见”的解决方案是有罪的(根据引文)[污染] 了实现细节的全局空间。”
因此,我的代码似乎同时包含了:(a) 所提及策略的目标和 (b) 一种潜在解决方案的不必要污染。那么替代解决方案是什么?
请回答其中一个或两个:
(1) 有没有办法在 cpp 文件中制作另一个 struct InnerComponent
的拷贝,这样字段 OuterComponent::m_inner
保持私有(private),类型 OuterComponent::InnerComponent
也保持私有(private),然而函数 FileScopeComputation
有某种方式做一些“等同于”访问 InnerComponent
实例上的数据?
我尝试过一些奇怪的选角方法,但没有什么看起来值得在书中推荐的。同时,根据我的经验,Lakos在书上推荐的东西,都是非常值得推荐的。
(2) 我是否完全误读了引用适用于哪种场景?如果是这样,那么引用实际上指的是什么 C++ 软件设计问题?还有什么其他问题涉及“结构的两个拷贝...一个在 h 文件中...另一个在 cpp 文件中”?
更新:
基于perceptive answer by dfri ,上面的代码确实可以通过最小的更改进行编译,这样:
OuterComponent::m_inner
字段保持私有(private)OuterComponent::InnerComponent
类型也保持私有(private)FileScopeComputation
函数有一些方法可以访问 InnerComponent
实例上的数据头代码多了一行代码:
...
private:
struct InnerUtil; // <-- this line was ADDED. all else is same as above.
struct InnerComponent
{
int foo = 0;
int bar = 0;
};
InnerComponent m_inner;
};
cpp文件代码变为:
struct OuterComponent::InnerUtil
{
static int FileScopeComputation( OuterComponent::InnerComponent i )
{
return i.bar - 3;
}
};
int OuterComponent::GetBar()
{
return InnerUtil::FileScopeComputation( m_inner );
}
最佳答案
有可能 Lakos 实际上指的是公共(public) API 委托(delegate)调用的单独命名的类型。引用和拉科斯之间有一种相似的感觉Factoring pattern (“Imp 和 ImpUtil 模式”),尤其是“ImpUtil”部分。
struct A {};
struct B {};
struct C {};
// widgetutil.h
// (definitions placed in widgetutil.cpp)
struct WidgetUtil {
// "Keep API in sync with Widget::foo".
static void foo(const A& b, const B& c, const C& a) {
// All implementation here in the util.
(void)a; (void)b; (void)c;
}
// "Keep API in sync with Widget::bar".
static void bar(const B& b, const C& c) {
// All implementation here in the util.
(void)b; (void)c;
}
};
// widget.h
// includes "widgetutil.h"
// Public-facing API
// (Ignoring the Imp pattern, only using the Util pattern).
struct Widget {
void foo(const A& a, const B& b) const {
// Only delegation to the util.
WidgetUtil::foo(a, b, c_);
}
void bar(const B& b) const {
// Only delegation to the util.
WidgetUtil::bar(b, c_);
}
private:
C c_{};
};
int main() {
const Widget w;
w.foo(A{}, B{}); // --> WidgetUtil::foo
}
这是一种将实现细节 ( WidgetUtil
) 与面向公众的 API ( Widget
) 分开的方法,同时也有助于测试:
WidgetUtil
的单元测试中对实现细节进行了单独单元测试,Widget
可以执行而无需担心 WidgetUtil
中的副作用成员,因为后者可以在 Widget
中使用静态依赖注入(inject)完全模拟(使其成为类模板)。如果我们回顾 Lakos 的引述(在 OP 中),WidgetUtil
也可以作为文件范围类放置在 widget.cpp
中源文件,隐藏在公共(public) API 之外。这将意味着更多的封装,但不会促进与上述分离相同的测试。
最后,注意制作Widget
类模板并不一定意味着污染 widget.h
的用户的翻译单元带有定义(需要在每个 TU 中编译,包括和实例化 Widget
)。作为Widget
被制作成一个类模板仅以方便测试,它的产品实现将永远只使用一个实例,即注入(inject)产品WidgetUtil
.这意味着可以将 Widget
的定义分开类模板成员函数的声明,就像非模板类一样,并显式实例化 Widget<WidgetUtil>
特化widget.cpp
.例如。使用以下方法:
Widget
来自类模板的头文件定义,到一个单独的-timpl.h
头文件,-timpl.h
头文件又包含在关联的 .cpp
中文件,该文件又包含 Widget
的显式实例化生产中使用的单一类型模板参数的类模板,即 WidgetUtil
.测试可以类似地包括 -timpl.h
header 并实例化 Widget
改为使用模拟的 util 类的类模板。
关于c++ - 给定一个 C++ 嵌套私有(private)结构类型,是否有从文件范围静态函数访问它的策略?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62616360/
今天我在一个 Java 应用程序中看到了几种不同的加载文件的方法。 文件:/ 文件:// 文件:/// 这三个 URL 开头有什么区别?使用它们的首选方式是什么? 非常感谢 斯特凡 最佳答案 file
就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引起辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the he
我有一个 javascript 文件,并且在该方法中有一个“测试”方法,我喜欢调用 C# 函数。 c# 函数与 javascript 文件不在同一文件中。 它位于 .cs 文件中。那么我该如何管理 j
需要检查我使用的文件/目录的权限 //filePath = path of file/directory access denied by user ( in windows ) File fil
我在一个目录中有很多 java 文件,我想在我的 Intellij 项目中使用它。但是我不想每次开始一个新项目时都将 java 文件复制到我的项目中。 我知道我可以在 Visual Studio 和
已关闭。此问题不符合Stack Overflow guidelines 。目前不接受答案。 这个问题似乎不是关于 a specific programming problem, a software
我有 3 个组件的 Twig 文件: 文件 1: {# content-here #} 文件 2: {{ title-here }} {# content-here #}
我得到了 mod_ldap.c 和 mod_authnz_ldap.c 文件。我需要使用 Linux 命令的 mod_ldap.so 和 mod_authnz_ldap.so 文件。 最佳答案 从 c
我想使用PIE在我的项目中使用 IE7。 但是我不明白的是,我只能在网络服务器上使用 .htc 文件吗? 我可以在没有网络服务器的情况下通过浏览器加载的本地页面中使用它吗? 我在 PIE 的文档中看到
我在 CI 管道中考虑这一点,我应该首先构建和测试我的应用程序,结果应该是一个 docker 镜像。 我想知道使用构建环境在构建服务器上构建然后运行测试是否更常见。也许为此使用构建脚本。最后只需将 j
using namespace std; struct WebSites { string siteName; int rank; string getSiteName() {
我是 Linux 新手,目前正在尝试使用 ginkgo USB-CAN 接口(interface) 的 API 编程功能。为了使用 C++ 对 API 进行编程,他们提供了库文件,其中包含三个带有 .
我刚学C语言,在实现一个程序时遇到了问题将 test.txt 文件作为程序的输入。 test.txt 文件的内容是: 1 30 30 40 50 60 2 40 30 50 60 60 3 30 20
如何连接两个tcpdump文件,使一个流量在文件中出现一个接一个?具体来说,我想“乘以”一个 tcpdump 文件,这样所有的 session 将一个接一个地按顺序重复几次。 最佳答案 mergeca
我有一个名为 input.MP4 的文件,它已损坏。它来自闭路电视摄像机。我什么都试过了,ffmpeg , VLC 转换,没有运气。但是,我使用了 mediainfo和 exiftool并提取以下信息
我想做什么? 我想提取 ISO 文件并编辑其中的文件,然后将其重新打包回 ISO 文件。 (正如你已经读过的) 我为什么要这样做? 我想开始修改 PSP ISO,为此我必须使用游戏资源、 Assets
给定一个 gzip 文件 Z,如果我将其解压缩为 Z',有什么办法可以重新压缩它以恢复完全相同的 gzip 文件 Z?在粗略阅读了 DEFLATE 格式后,我猜不会,因为任何给定的文件都可能在 DEF
我必须从数据库向我的邮件 ID 发送一封带有附件的邮件。 EXEC msdb.dbo.sp_send_dbmail @profile_name = 'Adventure Works Admin
我有一个大的 M4B 文件和一个 CUE 文件。我想将其拆分为多个 M4B 文件,或将其拆分为多个 MP3 文件(以前首选)。 我想在命令行中执行此操作(OS X,但如果需要可以使用 Linux),而
快速提问。我有一个没有实现文件的类的项目。 然后在 AppDelegate 我有: #import "AppDelegate.h" #import "SomeClass.h" @interface A
我是一名优秀的程序员,十分优秀!