如何从类定义中省略私有非虚拟方法?
假设我有如下内容:
a.hpp:
class B;
class A
{
private:
std::unique_ptr<B> b_;
}
a.cpp:
#include <something_complicated.hpp>
struct B
{
something_complicated x;
}
something_complicated& A::get_complicated() { return b_->x; }
不幸的是,在这种情况下,a.cpp 将无法编译,因为“get_complicated()”不是 A 的方法。
因此,我们可以尝试以下操作:
a.hpp:
class B;
class A
{
private:
std::unique_ptr<B> b_;
something_complicated& A::get_complicated();
}
但是 a.hpp 无法编译,因为没有定义 Something_complicated。
如果它是一个类,我们可以向前声明 some_complicated,但它可能是一个 typedef,所以这是不可能的。
我能想到的唯一方法是在不公开 b_ 也不在 a.hpp 中包含 Something_complicated.hpp 的情况下执行此操作:
a.cpp:
#include <something_complicated.hpp>
struct B
{
something_complicated x;
}
#define get_complicated ((b_->x))
当然,我不必定义宏来解决这个问题?还有其他选择吗?
Lets say I have something like the following:
a.hpp:
class B;
class A
{
private:
std::unique_ptr<B> b_;
}
a.cpp:
#include <something_complicated.hpp>
struct B
{
something_complicated x;
}
something_complicated& A::get_complicated() { return b_->x; }
Unfortunately, in this case, a.cpp will fall to compile because "get_complicated()" is not a method of A.
So, we can try this:
a.hpp:
class B;
class A
{
private:
std::unique_ptr<B> b_;
something_complicated& A::get_complicated();
}
But then a.hpp fails to compile because something_complicated isn't defined.
We could forward declare something_complicated if it is a class, but it's probably a typedef, so that is out.
The only way I can think of doing this without making b_ public nor including something_complicated.hpp in a.hpp is the following:
a.cpp:
#include <something_complicated.hpp>
struct B
{
something_complicated x;
}
#define get_complicated ((b_->x))
Surely I don't have to define a macro to get around this issue? Any alternatives?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
最简单的解决方案可能是将复杂类型的引用包装在类中,在
a.hpp
中向前声明,并在something_complicated.hpp
中定义它。a.hpp:
something_complicated.hpp:
现在
a.cpp
和任何需要使用复杂类型的东西都必须包含它的标头,但是任何只想使用class A
的东西都可以不需要。这是假设
A
的某些客户端有充分理由访问复杂的事物,但每个人都无法访问B
。在需要时允许访问B
并通过它处理复杂的事情会更简单。The easiest solution is probably to wrap a reference to the complicated type in a class, forward declare that in
a.hpp
, and define it insomething_complicated.hpp
.a.hpp:
something_complicated.hpp:
Now
a.cpp
and anything that needs to use the complicated type must include it's header, but anything that just wants to useclass A
does not need to.This is assuming that there's a good reason for some clients of
A
to access the complicated thing, but forB
to be inaccessible to everyone. It would be simpler still to allow access toB
when required, and get to the complicated thing through that.恐怕对于什么属于类、什么不属于类存在误解。
并非所有作用于类内部的方法都应该是类方法,毕竟我们已经有了
friend
函数。我知道很多人将 helper 方法声明为私有函数,但是这样做会引入不必要的依赖项(编译时)以及friend
的可见性问题。在处理 PIMPL 时,我倾向于不使用私有函数。相反,选择是:
Impl
(在您的情况下是B
)成为一个真正的类,具有自己的验证逻辑和真正的 APIstatic
免费函数(或在匿名命名空间中声明的函数)两者都很好,并且使用看起来最合适的那个。即:
我有意寻找尽可能少的方法,因为这些是唯一可能搞砸的方法我的类不变量越少,我就越有信心保持不变量。
就您的情况而言,由您决定哪种方法最适合您。
实际操作:
a.cpp
和你的没什么不同,是吗?
注意:与匿名命名空间相比,我更喜欢静态函数,因为它在阅读时更明显。命名空间引入了范围,并且在筛选文件时不容易浏览范围。您的情况可能会有所不同,两者都提供相同的功能(功能)。
I am afraid there is a misunderstand on what belong to the class, and what does not.
Not all methods that act on the internals of the class should be class methods, after all, we have
friend
functions already. I know that many people declare the helper methods as private functions, however doing so introduces needless dependencies (compile-time) and a visibility issue withfriend
s.When dealing with PIMPL, I tend not to use private functions. Instead, the choice is:
Impl
(B
in your case) a true class, with its own validation logic and true APIstatic
free functions (or functions declared in an anonymous namespace)Both are good, and use whichever seems most appropriate. Namely:
It is deliberate on my part to search to have as few methods as possible, because those are the only ones that can screw up my class invariants, and the less they are the more confident I can be that the invariants will be maintained.
In your case, it's up to you to decide which approach suits you best.
In Action:
a.cpp
Not so different from what you had, eh ?
Note: I prefer static functions to anonymous namespaces because it's more obvious when reading. Namespaces introduce scopes, and scope are not glanced easily when sifting through a file. Your mileage may vary, both offer identical functionality (for functions).
只是避免引用
a.hpp
中的something_complicated
即可。一种解决方案是将成员函数 get_complicated 替换为自由函数或另一个类的静态方法。
.h:
.cpp:
Just avoid referring to
something_complicated
ina.hpp
.One solution is to replace the member function
get_complicated
with a free function, or a static method of another class..h:
.cpp:
有什么问题:
a.hpp:
如果您的客户想要从 B 中得到一些复杂的东西,那么就让他们
#include
。What's wrong with:
a.hpp:
If your clients want to get something complicated out of B, then let them
#include <something_complicated.hpp>
.这正是您必须做的。我不明白 typedef 如何排除前向声明。
This is exactly what you have to do. And I don't see how being a typedef rules out a forward declaration.
如果您控制
something_complicated.hpp
,您可以执行标准库所做的操作:创建一个具有适当前向声明的something_complicated_fwd.hpp
,包括可能是或不是 typedef 的类型。If you control
something_complicated.hpp
you could do what the standard library does: Create asomething_complicated_fwd.hpp
that has appropriate forward declarations, including the types that may or may not be typedefs.