1

次のコードは、呼び出し元のオブジェクトのフレンドシップを許可せずにアクセスされるプライベート関数を持つインターフェイスからプライベートに継承するクラスを示しています。私はこれに困惑していますが、コンパイラーが思いつくより良い解決策 (コードのコンパイルと実行) を実際に見ることはできません。なぜこれが機能するのですか?

#include <iostream>

class IVisitor;

class IVisitable
{
public:
    virtual void Accept(IVisitor& visitor) const = 0;
};

class VisitableA;
class VisitableB;

class IVisitor
{
public:

    virtual void Visit(const VisitableA& a) = 0;

    virtual void Visit(const VisitableB& b) = 0;
};

class VisitableA : public IVisitable
{
public:
    virtual void Accept(IVisitor& visitor) const
    {
        visitor.Visit(*this);
    }
};

class VisitableB : public IVisitable
{
public:
    virtual void Accept(IVisitor& visitor) const
    {
        visitor.Visit(*this);
    }
};

class PrivateVisitor : private IVisitor
{
public:
    PrivateVisitor(IVisitable& v)
    {
        v.Accept(*this);    
    }

private:

    virtual void Visit(const VisitableA& a)
    {
        std::cout << "I saw A\n";
    }

    virtual void Visit(const VisitableB& b)
    {
        std::cout << "I saw B\n";
    }
};

int main(int argc, char* argv[])
{
VisitableA a;
VisitableB b;

PrivateVisitor p_a(a);
PrivateVisitor p_b(b);
} 
4

3 に答える 3

4

アクセス指定子はコンパイル時にのみチェックされ、適用されるオブジェクトの静的型がチェックされます。

PrivateVisitorコンストラクター内で、*thisオブジェクトは にキャストされIVisitorます。このコンテキストでは、継承のタイプは重要ではありませんPrivateVisitor。タイプ内にあるため、完全にアクセスできます。

オブジェクトはIVisitableオブジェクト (VisitableAまたはVisitableB) 内で使用され、Visitメンバー関数が呼び出されます。オブジェクトの動的PrivateVisitorタイプは ですが、静的タイプはIVisitor(参照のタイプは ですIVisitor&)。アクセス指定子は、両方のオーバーロードがpublicIVisitorであるクラスに対してチェックされるため、コンパイラは呼び出しを受け入れます。Visit

関数がpublicである基本クラスを介してアクセスが実行されたため、関数が最終的なオーバーライドでプライベートであるという事実は実際には重要ではありません。

于 2012-08-20T23:51:03.260 に答える
1

ここで重要なプライベートは、これです:

PrivateVisitor : private IVisitor

幸い、PrivateVisitorがIVisitorにキャストされる唯一の場所は、コンストラクターです。

PrivateVisitor::PrivateVisitor(IVisitable& v)
{
    v.Accept(*this);
}

そして、コンストラクターはクラスのプライベートベースにアクセスできます。

于 2012-08-20T23:38:05.707 に答える
0

private は、オブジェクト スコープではなく、クラス スコープにあります。

于 2012-08-20T23:35:00.897 に答える