mr_T
mr_T

Reputation: 2621

Is there any use for a class to contain only (by default) private members in c++?

Members of a class are by default private in c++.

Hence, I wonder whether there is any possible use of creating a class that has all its members (variables and functions) set by default to private.

In other words, does there exist any meaningful class definition without any of the keywords public, protected or private?

Upvotes: 25

Views: 2914

Answers (7)

Pablo H
Pablo H

Reputation: 659

A derived class can be all-private, even its virtual methods redefining/implementing base-class methods.

To construct instances you can have friend classes or functions (e.g. factory), and/or register the class/instance in a registry.

An example of this might be classes representing "modules" in a library. E.g. wxWidgets has something like that (they are registered and do init/deinit).

Upvotes: 0

manlio
manlio

Reputation: 18902

There is a pattern, used for access protection, based on that kind of class: sometimes it's called passkey pattern (see also clean C++ granular friend equivalent? (Answer: Attorney-Client Idiom) and How to name this key-oriented access-protection pattern?).

Only a friend of the key class has access to protectedMethod():

// All members set by default to private
class PassKey { friend class Foo; PassKey() {} };

class Bar
{
public:
  void protectedMethod(PassKey);
};

class Foo
{
  void do_stuff(Bar& b)
  {
    b.protectedMethod(PassKey());  // works, Foo is friend of PassKey
  }
};

class Baz
{
  void do_stuff(Bar& b)
  {
    b.protectedMethod(PassKey()); // error, PassKey() is private
  }
};

Upvotes: 24

Sylvain Leroux
Sylvain Leroux

Reputation: 52000

Application wide resource acquisition ?

#include <iostream>

class C {
    C() {
        std::cout << "Acquire resource" << std::endl;
    }


    ~C() {
        std::cout << "Release resource" << std::endl;
    }

    static C c;
};


C C::c;

int main() {
    return 0;
}

As stated in comments below, I have I mind an industrial application that had to "lock" some hardware device while the program was running. But one might probably found other use for this as, after all, it is only some "degenerated" case or RAII.


As about using "private" methods outside the declaration block: I use a static member here. So, it is declared at a point where private members are accessible. You're not limited to constructor/destructor. You can even (ab)use a static methods and then invoke private instance methods using a fluent interface:

class C {
    C() { std::cout << "Ctor " << this << std::endl; }
    ~C() { std::cout << "Dtor" << this << std::endl; }

    static C* init(const char* mode) {
        static C theC;

        std::cout << "Init " << mode << std::endl;
        return &theC;
    }

    C* doThis() {
        std::cout << "doThis " << std::endl;

        return this;
    }

    C* doThat() {
        std::cout << "doThat " << std::endl;

        return this;
    }

    static C *c;
};


C *C::c = C::init("XYZ")
            ->doThis()
            ->doThat();

int main() {
    std::cout << "Running " << std::endl;
    return 0;
}

That code is still valid (as all C members are accessible at the point of declaration of C::c). And will produce something like that:

Ctor 0x601430
Init XYZ
doThis 
doThat 
Running 
Dtor0x601430

Upvotes: 16

Loren Pechtel
Loren Pechtel

Reputation: 9093

An admittedly ugly case from many, many years ago and not in C++ but the idea would still apply:

There was a bug in the runtime library. Actually fixing the offending code would cause other problems so I wrote a routine that found the offending piece of code and replaced it with a version that worked. The original incarnation had no interface at all beyond it's creation.

Upvotes: 0

BЈовић
BЈовић

Reputation: 64223

No, there is no sense in creating a class without public member variable and/or functions, since there wouldn't be a way to access anything in the class. Even if not explicitly stated, the inheritance is private as well.

Sure, you could use friend as suggested, but it would create unneeded convolution.


On the other hand, if you use struct and not class to define a class, then you get everything public. That may make sense.

For example :

struct MyHwMap {
  unsigned int field1 : 16;
  unsigned int field2 : 8;
  unsigned int fieldA : 24;
};

Upvotes: 1

Benjamin Lindley
Benjamin Lindley

Reputation: 103703

Tag dispatching. It's used in the standard library for iterator category tags, in order to select algorithms which may be more efficient with certain iterator categories. For example, std::distance may be implemented something like this: (in fact it is implemented almost exactly like this in gnu libstdc++, but I've modified it slightly to improve readability)

template<typename Iterator>
typename iterator_traits<Iterator>::difference_type
distance(Iterator first, Iterator last)
{
      return __distance(first, last,
             typename iterator_traits<Iterator>::iterator_category());
}

Where __distance is a function which is overloaded to behave more efficiently for std::random_access_iterator_tag (which is an empty struct, but could just as easily be a class), simply using last - first instead of the default behavior of counting how many increments it takes to get first to last.

Upvotes: 18

AlexanderBrevig
AlexanderBrevig

Reputation: 1987

Meaningful? Good practice? Probably not, but here goes:

class DataContainer {
    friend class DataUser;
    int someDataYouShouldNotWorryAbout;
};

class DataUser {
public:
    DataUser() {
        container.someDataYouShouldNotWorryAbout = 42;
    }
private:
    DataContainer container;
};

Upvotes: 7

Related Questions