2

operator<<そのため、内部データを出力ストリームに出力できるようにオーバーロードしたいクラスがあります。これはデバッグ目的でのみ実行したいので、どういうわけか完全にoperator<<外部から隠して*.cpp、クラスの実装が存在するファイル内からのみアクセスできるようにします。operator<<私のクラスからメンバー変数へのアクセスを与えるために、私はそれをそれの友達にする必要があります。ただし、クラスで友達を宣言 operator<<すると、外の世界の誰もが operator<<このクラスを呼び出すことができます...

これを行うために通常のプライベートメンバー関数を作成できることは知っていますが、を使用するデバッグマクロがすでにいくつかあるoperator<<ので、これを何らかの方法で実行できるかどうか疑問に思いました。

4

5 に答える 5

2

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)。

于 2013-03-26T23:50:58.463 に答える
0
#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")))

このように、ライブラリユーザーはこの関数をリンクできませんでした。

于 2013-03-26T22:39:13.460 に答える
0

1つの翻訳ユニットがアクセスできる場合は、で卑劣で移植性のないことを行わない限り、どの翻訳ユニットもアクセスできる可能性があります#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<<;

// ...
于 2013-03-26T22:56:35.987 に答える
0

operator<<をクラスの友達として宣言しますが、使用できるようにするファイルでとして定義します。static

これには1つの小さな欠点があります。定義したファイルの外部で使用しようとすると、実際に必要なコンパイラエラーではなく、リンカエラーが発生するだけです。一方で、それでも保護がまったくないよりもはるかに優れています。

これが簡単なデモです。まず、クラス定義を含むヘッダーと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;
}

次に、オペレーターにアクセスできない2番目のファイル:

#include "trash.h"

void junk(X const &x) {
    // un-comment the following, and the file won't link:
    //std::cout << x; 
}

この場合、ファイルレベルのstatic関数の代わりに匿名の名前空間を使用できないことに注意してください。試してみると、operator<<許可したい場合でも、のあいまいなオーバーロードとして表示されます。

于 2013-03-26T23:16:57.353 に答える
0

さて、あなたの答えをすべて読んで、長い間頭を悩ませた後、私は次のことを思いついた。私はプライベート継承を使用してクラスのすべてのデータを格納し、出力関数をプライベート基本クラスのフレンドにします。また、ユーザーがこの基本クラスをインスタンス化できないようにするには、抽象化する必要がありました。これが優れたソフトウェアエンジニアリングであるとは言いません。また、このアプローチは、概念実証として、私の好みには少し複雑すぎます。これをgcc4.7.2でコンパイルし、次のスイッチを使用しました。-std = c ++ 98 -Wall -Wextra -pedantic -g

ヘッダーファイルclass.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;
}
于 2013-03-26T23:55:58.837 に答える