3

What's the recommendation regarding conditionally defining member functions in a C++ class? (The question is centered around limiting the external exposure of some classes in a DLL - specifically when those classes are passed in as a parameter). Obviously this isn't something you want to do to data members, but functions should be OK shouldn't they?

For example:

class A
{
public:
    void func1();

#ifdef _CONDITION_
    void func2(B b);
#endif    
};

Edited: Added public modifier to avoid example confusion.

Nicholas
  • 1,392
  • 16
  • 38
  • could you elaborate why you want to do this? The #indef (preprocessor) is a before-compile time thing so you can't use it to make the member function appear in some calls and not in others. – seand Apr 16 '11 at 02:24
  • When using a shared library (DLL) from C++ you generally still include the header files of the classes compiled in the library. In this case I don't want the software using the DLL to see some of the classes referenced inside these header files. – Nicholas Apr 16 '11 at 02:28
  • oic; you're creating different flavors of headers files, one for internal use and another for the external interface? It sounds like your technique would be fine. If this is similar to your needs i've seen cases where #if's control whether stuff like __declspec(dllexport) gets emitted. – seand Apr 16 '11 at 02:32
  • @seand Is this fine? If the dll and the program sees different definitions for the class, they build different internal representations and the types, although have the same name, no longer match. If that is the case, sounds like an awful solution to me. – lvella Apr 16 '11 at 02:41
  • @ivella you're right! internal structures (vtables etc) would be out of whack. Perhaps best to only dllexport the functions that are intended to be visible outside if that's @Nicolas-s original goal. – seand Apr 16 '11 at 02:46

4 Answers4

2

Not entirely sure what you're asking, but if the member functions are intended to be private to the class use the 'private:' keyword to make them private.

If instead they're intended to be used by other classes within the context of the module where the class lives, but you don't want external entities knowing about them, make them public but derive the class from an 'interface' base class, and expose that interface base class to external entities.

finsprings
  • 130
  • 8
  • Well yes, but unfortunately the 'private' keyword doesn't stop an application linking to a DLL at compile time from 'requiring' full definitions of the member functions parameters. Also using the 'private' keyword limits how that member function can be used inside the data package. – Nicholas Apr 16 '11 at 02:53
2

Generally if you wont want to expose parts of an exported class, then you should consider the option of not exposing the class, but instead providing an abstract interface that your class inherits from.

eg.

class AbstractExportedInterface
{
public:
    virtual void do_stuff() = 0;
};

class HasStuffIDontWantToExport : public AbstractExportedInterface
{
public:
    void do_stuff();
    void do_other_stuff_that_i_dont_export();
};

then you would operate on the assumption that you are providing a HasStuffIDontWantToExport* to the DLL user and they only have headers for AbstractExportedInterface.

EDIT: Response to first comment

If you have some types (3rd party or otherwise) that you want your client of the DLL to be able to use in some way, but you dont want them to have full access to those types, and you dont have the flexibility to use a direct inheritance hierarchy to create an abstract interface. You might be able to use pimpl pattern to create proxy interfaces for each of the types you want your client to have limited usage of?

eg.

class ExportedAbstractProxyObject
{
public:
    virtual void do_stuff() = 0;
};


#include <3rdPartyType.h>

class ProxyObject
{
public:
    void do_stuff() { pimpl_.actually_do_stuff(); }
private:
    3rdPartyType pimpl_;
};


class ExportedAbstractProxyOtherObject
{
public:
    virtual void do_stuff_with_thing(ExportedAbstractProxyObject* thing) = 0;
};


class ProxyOtherObject
{
public:
    void do_stuff_with_thing(ExportedAbstractProxyObject* thing) { thing->do_stuff(); }
};

So then you can happily export whatever interfaces you like, and completely hide the implementation and 3rd party types inside your DLL. The downside is you obviously then have to create all those proxy object interfaces.

Vusak
  • 1,420
  • 9
  • 12
  • I like the inheritance approach, however it is not always something you have control over. For example, when the DLL being created is linked to a static library of functions created by third parties. – Nicholas Apr 16 '11 at 02:50
0

That sort of thing is generally done using public/protected/private declarations, and possibly friends, rather than preprocessor conditions. But in one program I've written where it was more of a problem to declare a certain set of functions as private or protected (because of the number of stand-alone functions that needed access to them), I prefixed the pseudo-private function names with an underscore (along with clear comments explaining why), to make it clear to the reader that those functions weren't meant for general use.

Head Geek
  • 38,128
  • 22
  • 77
  • 87
  • Yes, but with an underscore you still have to define the types used in these functions. And therefore more header files or forward declarations must be provided to users of the DLL. I really would just prefer to provide say 2 header files rather than 60. – Nicholas Apr 16 '11 at 03:02
0

You say you want to prevent visibility of some of the classes, but your example only hides a single method.

If a class doesn't form part of the "public" interface of your DLL you don't need to publish the header. For example:

// foo.h
class Bar;

class Foo
{
    private Bar* _bar;
    ...
}

Here "Bar" is part of the implementation so there is no need to ship its header. If Bar is used only by Foo, you could also define it within the private/protected scope in Foo.

David
  • 2,226
  • 32
  • 39
  • Unfortunately in my case I would prefer to keep the conditionally compiled functions public. – Nicholas Apr 16 '11 at 02:57
  • Then I would recommend Vusak's approach. Making the client depend on the interface or abstract class is the basis of inversion-of-control (IoC) and allows you to write highly modular code that can easily be unit tested. – David Apr 16 '11 at 03:09