Search code examples
c++constructordestructorfriend

C++ library making, hiding destructor/constructor without friend in header


I have to make a shared library and now I'm facing with the following problem. (MSVC2015). I want to hide constructor/destructor like in class A, and I have a "factory" class like B.

class A {
     public:
     private:
         A() {};
         ~A() {};
     friend class B;
};

class B {
   public:
   B() {};
   ~B() {};
    A * Create() { return new A(); };
};

So I compile these two classes to create a .lib and a .dll. My question is, that if i give the user the header file which contains class A's definition plus the .lib and .dll but remove the line friend class B from this header then will it be a valid solution? In other words: is "friend class" is needed in only compile time or is it needed in runtime too?

Thank you for your help!


Solution

  • If you compile it with the friend line and then remove the friend line, your user can always add it again. Your user might also be able to change the function from private to public.

    If the implementation of A::A() is exported by your library is a different question and under windows determined by the declspec(dllexport/import) attribute, so independent from private/public it might be available to the user or not. From what i've seen so far, public, private and friend declarations have no impact on the compiled dll and using member-pointers you can even get access to private members without compiling a dll. However no guarantee on this point.

    The real question is: Why would you want to do this?
    If you state in your header that this constructor is private and only accessibly by B, provide a factory function in B and (hopefully) state in your documentation that the user should use this factory, then you have done everything reasonable to keep the user from using this class. If he still does, it is not your fault anymore.

    Edit: (challenge accepted)

    I just compiled the following .dll with MSVC 2015:

    //class.cpp
    #include "class.h"
    
    void bar(C & c)
    {
        c.privatePrint();
    }
    
    //class.h
    #pragma once
    #include <string>
    #include <iostream>
    
    class C {
    private:
        std::string str;
        C() :str("foo") {}
    
        void print() {
            std::cout << str << std::endl;
        }
    
        void privatePrint() {
            std::cout << "private " << str << std::endl;
        }
    
        friend _declspec(dllexport) void bar(C& c);
    };
    
    _declspec(dllexport) void bar(C& c);
    

    And loaded it in the following .exe:

    //main.cpp
    #include <iostream>
    #include "class.h"
    #pragma comment(lib,"../Debug/lib.lib")
    
    int main(){
        C c;
    
        bar(c);
        c.print();
    }
    
    //class.h
    class C {
    public:
        std::string str;
        C() :str("foo") {}
    
        void print() {
            std::cout << str << std::endl;
        }
    };
    
    _declspec(dllimport) void bar(C& c);
    

    Output:

    private foo
    foo
    

    So what we learn is: The constructor here is defined inside the class definition, so even without _declspec(dllexport/import) the executable has access to it. We in fact can change private to public and have access to the constructor. Same is true for the member-function print().
    And even though i not only omitted the fried declaration for bar() in the executables header but also the complete function definition used by bar() it is no problem for bar to print the string - simply because the code for bar() is already compiled in the .dll.

    So obviously a class is totally defined by its member-variables and their layout, neither functions nor access specifiers need to be the same. However i don't state that this is compliant to the Standard, guaranteed to work or should be done at all