Search code examples
c++visual-studio-2015class-visibility

How to fake "visibility of class" (not of functions) in C++?


There is no feature that control visibility/accessibility of class in C++.

Is there any way to fake it?
Are there any macro/template/magic of C++ that can simulate the closest behavior?

Here is the situation

Util.h (library)

class Util{   
    //note: by design, this Util is useful only for B and C
    //Other classes should not even see "Util"
    public: static void calculate(); //implementation in Util.cpp
};

B.h (library)

#include "Util.h"
class B{ /* ... complex thing */  };

C.h (library)

#include "Util.h"
class C{ /* ... complex thing */  };

D.h (user)

#include "B.h"    //<--- Purpose of #include is to access "B", but not "Util"
class D{ 
    public: static void a(){
        Util::calculate();   //<--- should compile error     
        //When ctrl+space, I should not see "Util" as a choice.
    }
};

My poor solution

Make all member of Util to be private, then declare :-

friend class B;
friend class C;

(Edit: Thank A.S.H for "no forward declaration needed here".)

Disadvantage :-

  • It is a modifying Util to somehow recognize B and C.
    It doesn't make sense in my opinion.
  • Now B and C can access every member of Util, break any private access guard.
    There is a way to enable friend for only some members but it is not so cute, and unusable for this case.
  • D just can't use Util, but can still see it.
    Util is still a choice when use auto-complete (e.g. ctrl+space) in D.h.

(Edit) Note: It is all about convenience for coding; to prevent some bug or bad usage / better auto-completion / better encapsulation. This is not about anti-hacking, or prevent unauthorized access to the function.

(Edit, accepted):

Sadly, I can accept only one solution, so I subjectively picked the one that requires less work and provide much flexibility.

To future readers, Preet Kukreti (& texasbruce in comment) and Shmuel H. (& A.S.H is comment) has also provided good solutions that worth reading.


Solution

  • One possible solution would be to shove Util into a namespace, and typedef it inside the B and C classes:

    namespace util_namespace {
    
        class Util{
        public:
            static void calculate(); //implementation in Util.cpp
        };
    };
    
    class B {
    
        typedef util_namespace::Util Util;
    
    public:
    
        void foo()
        {
            Util::calculate(); // Works
        }
    };
    
    class C {
    
        typedef util_namespace::Util Util;
    
    public:
    
        void foo()
        {
            Util::calculate(); // Works
        }
    };
    
    class D {
    
    public:
    
        void foo()
        {
            Util::calculate(); // This will fail.
        }
    };
    

    If the Util class is implemented in util.cpp, this would require wrapping it inside a namespace util_namespace { ... }. As far as B and C are concerned, their implementation can refer to a class named Util, and nobody would be the wiser. Without the enabling typedef, D will not find a class by that name.