Discussion:
Moving private functions out of header files
(too old to reply)
Bjarke Hammersholt Roune
2011-06-04 07:40:24 UTC
Permalink
Summary: Should I, and if so how, move private member functions out of
header files when they refer to a private inner class?

Consider this code, where I'd like to move implementationDetail(int)
to the implementation file:

class Outer {
public:
// ...
private:
int implementationDetail(int v);
struct Inner {
// ...
};
vector<Inner> v;
};

Here implementationDetail is something that someone who wants to use
the interface of Outer doesn't need to know about, so it is private.
Unfortunately, it is still there in the header file and if I change
the signature of implementationDetail, that will trigger a
recompilation of files that include Outer's header file. If
implementationDetail only refers to few member variables I therefore
prefer to move its declaration out of the header file and instead make
it a free-standing function in the implementation file. Something like
this:

// in implementation file
namespace {
int implementationDetail(int v) {return v + 1;}
}

This way header files get smaller, there will be fewer recompilations
and someone (e.g. me in a week) reading my header file to get its
interface will have less stuff to mentally tune out. So far so good.
However, this cannot be done if implementationDetail takes an Inner:

// in implementation file
namespace {
// error: Outer::Inner is private
int implementationDetail(Outer::Inner inner) {
return inner.a + inner.b;
}
}

The problem is that Inner is private. This can sometimes be solved by
moving Inner into the implementation file just as we did for
implementationDetail. This won't work here because we can't have a
vector<Inner> member then - it would work if we had an Inner* member
instead. So inner private classes defeat moving implementation details
out of header files in this way.

What's the best practice here? One way is to declare defeat and just
leave implementationDetail in the header file, though I'm not too
happy about that.



Now I do have a work-around that technically works, but I don't like
it much. You can do it this way:

// in implementation file
namespace {
template<class TemplateInner>
int implementationDetail(TemplateInner inner) {
return inner.a + inner.b;
}
}

If you pass a private class as a template parameter to a function then
that function gains access to the class even if it is private. So if
you call implementationDetail with an Outer::Inner as a parameter,
this code will do the right thing, but it's really not pretty. Is
there a better way?


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Daniel Krügler
2011-06-04 13:52:03 UTC
Permalink
Am 04.06.2011 09:40, schrieb Bjarke Hammersholt Roune:
> Summary: Should I, and if so how, move private member functions out of
> header files when they refer to a private inner class?

[..]

> What's the best practice here? One way is to declare defeat and just
> leave implementationDetail in the header file, though I'm not too
> happy about that.

I don't think that there exists a single best answer to that question,
because it still remains unclear to me what the criteria and their
weights are. But if you just want to reduce the number of private
functions that are no overriders of a base class, you could simply
declare a class or class template (depending on your actual scenario) as
a friend, e.g.

class Outer {
public:
// ...
private:
friend class Implementationdetail;
struct Inner {
// ...
};
vector<Inner> v;
};

This allows you to get rid of all private member functions in the class
which is intended to be used by clients. All functions that you would
have declared in Outer can be defined as static functions of class
Implementationdetail. If you want Implementationdetail to be an inner
class of Outer, just declare it as

class Outer {
public:
// ...
private:
class Implementationdetail;
struct Inner {
// ...
};
vector<Inner> v;
};

HTH & Greetings from Bremen,

Daniel Krügler


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Edward Diener
2011-06-05 13:15:15 UTC
Permalink
On 6/4/2011 3:40 AM, Bjarke Hammersholt Roune wrote:

> Summary: Should I, and if so how, move private member functions out of
> header files when they refer to a private inner class?
>

Look up 'pimpl' idiom.


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Francis Glassborow
2011-06-06 03:42:37 UTC
Permalink
On 05/06/2011 14:15, Edward Diener wrote:
>
> On 6/4/2011 3:40 AM, Bjarke Hammersholt Roune wrote:
>
>> Summary: Should I, and if so how, move private member functions out of
>> header files when they refer to a private inner class?
>>
>
> Look up 'pimpl' idiom.

I don't think that really helps in this case.
As the inner class is used as type argument to a template (std::vector)
I suspect that the inner class must be fully defined within the
definition of the outer class.

Now if the problem is that the OP wants private member functions of
outer to take arguments of type inner I think the answer is to remove
these from the class scope into a freestanding class that is defined in
the implementation file of outer and that outer grants friendship to (so
that it will have access to all parts of outer.


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
werasm
2011-06-06 18:46:12 UTC
Permalink
On Jun 4, 9:40 am, Bjarke Hammersholt Roune <***@gmail.com>
wrote:
> Summary: Should I, and if so how, move private member functions out of
> header files when they refer to a private inner class?
>
> Consider this code, where I'd like to move implementationDetail(int)
> to the implementation file:
>
> class Outer {
> public:
> // ...
> private:
> int implementationDetail(int v);
> struct Inner {
> // ...
> };
> vector<Inner> v;
>
> };
>

Why can't you use another level of indirection...

Move Inner into Impl, and let Outer::Impl contain the vector
and everything else that needs to be private.

//.h
class Outer
{
//...
private:
struct Impl;
Impl* pimpl_; //or scoped_ptr should you prefer
};

//.cpp

//...
struct Outer::Impl
{
class Inner
{
//...
};
//Public members of inner visible to
// to all members of Outer::Impl...
void implementationDetail( Inner& inner );

std::vector<Inner> inner_seq_;
};

[snip]

Kind regards,

W


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Andrew
2011-06-07 16:30:58 UTC
Permalink
On Jun 4, 7:40 am, Bjarke Hammersholt Roune <***@gmail.com>
wrote:
> Summary: Should I, and if so how, move private member functions out of
> header files when they refer to a private inner class?
>
> Consider this code
[snip]
> Here implementationDetail is something that someone who wants to use
> the interface of Outer doesn't need to know about, so it is private.
> Unfortunately, it is still there in the header file and if I change
> the signature of implementationDetail, that will trigger a
> recompilation of files that include Outer's header file.

The standard way to solve this problem is via the pimpl idiom. In the
public header file fwd declare a pointer to a implementation class
which has all the implementation buggins (including use of inner
classes) that you are hiding from your clients. The ctor allocates the
pimpl, the dtor deletes it. The public methods just fwd to the impl
class.

Regards,

Andrew Marlow


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Loading...