schumacher574
schumacher574

Reputation: 1129

Where to define struct only to be used as private member variable?

Take the following header file example, where Bar is a struct:

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

I only want Bar to be accessible as a private member variable for Foo. What is the proper way to declare and define Bar?

Option 1: define in header?

I'd like to avoid this, as I don't want Bar to be usable outside the Foo class scope.

struct Bar
{
    int a;
    int b;
    ...
};

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

Option 2: forward declare in header, define in cpp?

Not sure if this is legal, as how will the compiler know the size of Foo strictly from the header if Bar's definition isn't directly available? Also, will this hide Bar from other files that include the header?

header:

struct Bar;

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

implementation file:

struct Bar
{
    int a;
    int b;
    ...
};

Option 3: declare within class

Maybe the best option to limit scope, but potentially messy?

class Foo
{
    ...
private:
    struct Bar
    {
        int a;
        int b;
        ...
    };

    Bar _bar;
};

Upvotes: 19

Views: 9475

Answers (3)

πάντα ῥεῖ
πάντα ῥεῖ

Reputation: 1

Option 3: declare within class

Maybe the best option to limit scope

Of course, that's the best way to limit scope and doesn't pollute the namespace. Go for option 3.

but potentially messy?

I didn't get your concerns (you may wanted to elaborate that in your question), there's nothing messy with that at all.

Note: Whenever needed to make a roundtrip from clients with it, they can use the auto keyword to refer to Bar variables.


Another option as mentioned by R.Sahu, is to use the Pimpl Idiom:

struct FooData;
class Foo {
    ...
private:

    std::unique_ptr<FooData> data_; // Note I not prefer to use leading underscores

public:
    Foo();
};

And in Foo's translation unit:

namespace {
    struct FooData;
    {
        int a;
        int b;
        ...
    };
}

Foo::Foo() : data_(std::make_unique<FooData<()) {}

Upvotes: 7

Arnav Borborah
Arnav Borborah

Reputation: 11769

Option 1: define in header?

I'd like to avoid this, as I don't want Bar to be usable outside the Foo class scope.

With option one, you just answered your own question.

Option 2: forward declare in header, define in cpp

Same problem here as option 1(scope visibility ), but only advantage is Bar's implementation won't be visible to other .cpp files.

Option 3: declare within class

Option 3 is the best, since it fulfills the purpose you ask for, and only that. In addition, with that Bar is available to the whole class. Also, nesting the class prevents unnecessary clutter in your code, as nothing except Foo can access Bar. And it definitely does NOT seem messy, and plus, you could declare just the struct like this:

class Foo
{
private:
    struct Bar {int a, int b};
    //.....
};

For a small class, and that seems ok since it is a 1-liner. A disadvantage would be forward-declaring the class, not possible, as seen in this answer: https://stackoverflow.com/a/951245/6525260.

Upvotes: 4

SergeyA
SergeyA

Reputation: 62553

For the option 2 to compile, _bar should be a pointer. Option 3 is best, since it doesn't pollute namespace.

Upvotes: 12

Related Questions