私人朋友运营商<<
private friend operator<<
所以我有一个类,我想重载operator<<
以便能够输出将其内部数据输出流。我想这样做只是为了调试从而以某种方式向外界完全隐藏CCD_ 2,使得它将仅从CCD_ 3文件内可访问我的类的实现存在。向成员授予operator<<
访问权限类中的变量,我必须使它成为它的朋友operator<<
班上的朋友让外界的任何人都可以打电话这节课上的operator<<
。。。
我知道我可以做一个常规的私人会员功能来做这件事,但我已经有了一些使用CCD_ 7的调试宏,所以我想知道是否有可能以某种方式完成这项工作。
您可以将operator<<
功能移动到助手代理类。当代理用作<<
的RHS时,将打印原始对象。定义从原始到代理的private
隐式转换。现在任何人都可以访问operator<<
,但只有类才有能力构造代理。
代码:
class private_printable {
int state;
struct proxy {
private_printable const &r;
};
operator proxy () const { return { * this }; }
friend std::ostream & operator << ( std::ostream & s, proxy const & o )
{ return s << o.r.state; }
public:
private_printable() : state( 5 ) {}
void debug() { std::cout << * this << 'n'; }
};
请注意,代理不需要加好友。与正常的做事方式相比,唯一的变化是存在代理和转换功能。friend operator<<
是通过依赖于参数的查找找到的,没有命名空间作用域声明,即使它不接受private_printable
参数。然后转换使其可行。不要认为更清洁的解决方案是可能的:v(。
#ifdef WIN32
# define DLL_LOCAL
# define DLL_PUBLIC __declspec(dllexport)
#else
# define DLL_LOCAL __attribute__ ((visibility ("hidden")))
# define DLL_PUBLIC
#endif
class DLL_PUBLIC Example
{
DLL_LOCAL friend std::ostream& operator << ( std::ostream& os_, const Example& inst_ );
...
};
在Windows DLL中:不要导出友元函数。
在gcc中:用__attribute__ ((visibility ("hidden")))
隐藏
通过这种方式,库用户无法链接此函数。
如果一个翻译单元可以访问,那么任何翻译单元都可以访问,除非你用#ifdef
做了一些卑鄙且不可移植的事情。
但你可能会意外地使其难以使用:
// example.hpp
#ifndef EXAMPLE_CLASS_HPP
#define EXAMPLE_CLASS_HPP
#include <ostream>
class Example;
namespace Example_debug {
std::ostream& operator<<(std::ostream&, const Example&);
}
class Example {
public:
// ...
private:
void debug_print(std::ostream&) const;
friend std::ostream& Example_debug::operator<<(
std::ostream&, const Example&);
};
#endif
// example.cpp
#include "example.hpp"
std::ostream& Example_debug::operator<<(std::ostream& os, const Example& obj) {
obj.debug_print(os);
return os;
}
using Example_debug::operator<<;
// ...
将operator<<
声明为类中的朋友,但在希望其可用的文件中将其定义为static
。
这确实有一个小缺点:试图在您定义它的文件之外使用它只会导致链接器错误,而不是您真正喜欢的编译器错误。另一方面,这仍然比完全没有保护要好很多。
下面是一个快速演示。首先,使用类定义的头,并声明一个函数junk
,我们将使用它来测试对操作符的访问:
// trash.h
#include <iostream>
class X {
friend std::ostream &operator<<(std::ostream &, X const &);
};
void junk(X const &);
然后是我们定义X
和运算符的文件,因此我们应该能够从这里访问运算符:
#include "trash.h"
static std::ostream &operator<<(std::ostream &os, X const &x) {
return os << "x";
}
int main() {
X x;
std::cout << x;
junk(x);
return 0;
}
然后是第二个不应该访问操作员的文件:
#include "trash.h"
void junk(X const &x) {
// un-comment the following, and the file won't link:
//std::cout << x;
}
请注意,在这种情况下,我们不能使用匿名命名空间来代替文件级operator<<
0函数——如果您尝试,它将显示为operator<<
的模糊重载,即使在我们希望允许的情况下也是如此。
好吧,所以在阅读了你们所有的答案并挠头了很长时间之后,我想出了下面的办法。我使用私有继承来存储类的所有数据,并使输出函数成为私有基类的友元。另外,为了禁止用户实例化这个基类,我不得不使它抽象化。我并不认为这是一个好的软件工程,而且这种方法也有点过于复杂,不符合我的口味,作为概念的证明。我用以下开关用gcc 4.7.2编译了这个:-std=c++98-墙-Wextra-迂腐-g
在头文件类.h:中
#ifndef CCLASS_H
#define CCLASS_H
#include <iostream>
class CDataBase
{
protected:
/// all data members will go here
int m_data;
CDataBase(int data = 0) : m_data(data) { }
/**
* Make the base virtual, so that it cannot be instantiated
*/
virtual ~CDataBase(void) = 0;
/// and this function is a friend of only the base class
friend std::ostream & operator<<(std::ostream & os, const CDataBase & base);
};
class CMyClass : private CDataBase
{
public:
CMyClass(void) : CDataBase(42) { }
virtual ~CMyClass(void) { }
void test(void);
};
#endif
在实现文件Class.cpp 中
#include "CClass.h"
std::ostream & operator<<(std::ostream & os, const CDataBase & base)
{
os << base.m_data;
return os;
}
CDataBase::~CDataBase(void)
{
}
void CMyClass::test(void)
{
std::cout << *this << std::endl;
}
在其他文件中:
#include "CClass.h"
#include <iostream>
int main(void)
{
CMyClass cls;
cls.test(); // this works
// this failes, because CDataBase is abstract
//CDataBase base;
// this fails as well, because CDataBase is inaccessible
//std::cout << cls << std::endl;
return 0;
}
- 呼叫运营商<<临时
- 两个运营商的一些奇怪的冲突<<
- 如何在 CPP 中访问家长的运营商
- 如何明确调用好友流运营商
- 私有运营商删除会触发 GCC 和 Clang 的编译时错误,但不会在 MSVC 上触发编译时错误
- 使用运营商New分配的数据结构是否有任何副作用
- "Inheriting"移动运营商?
- 朋友ostream&运营商<<无法访问私人会员
- 为什么在下面的代码返回类型中是用于运营商重载的类类型
- 范围的枚举(枚举类)关系运营商
- 为什么“操作员”需要const但不是为“运营商&lt;”
- 对这两个分配运营商之间的不同感到困惑
- 我的班级意外加法运营商
- OpenACC - C++"新"运营商问题
- c 对运营商的一致性是新的,有多少重要
- 为什么我不能使私人运营商成为新的并使用默认实现?
- 全球取代所有新运营商
- 包装C 朋友在Cython中的非会员运营商
- 没有匹配的“运营商&lt;&lt;”
- 运营商&lt;&lt;无法访问班级的私人int