Inheritance, Class declaration and header files

S

Sim Smith

This is the problem:

I have to inherit a third party class file in my library. If I
directly do it, I will have to ship the third party header files to my
customers as well. I do not want to ship the third party header files
to my customers. What is the most elegant way to handle this problem.

For example:
// MyClass.h

#include "ThirdPartyClass.h"

class MyClass : public ThirdPartyClass
{
};

I would prefer keeping my class definitions in the header files.

Thanks
Sim
 
D

Dave Townsend

Sim Smith said:
This is the problem:

I have to inherit a third party class file in my library. If I
directly do it, I will have to ship the third party header files to my
customers as well. I do not want to ship the third party header files
to my customers. What is the most elegant way to handle this problem.

For example:
// MyClass.h

#include "ThirdPartyClass.h"

class MyClass : public ThirdPartyClass
{
};

I would prefer keeping my class definitions in the header files.

Thanks
Sim

Do you really need to inherit from the thirdparty ? If you don't then you
can compose the thirdparty class as a member variable in your class. This
is the Design Patterns book "prefer composition over inheritance" idiom.

class myclass : public .......whatever bases you need.....
{

MyClass( .....)
{
_thirdPartyClass = new ThirdPartyClass();
}
private:
class ThirdPartyClass* _thirdPartyClass

};

Since the member is a pointer, you can get away with a forward
declaration,or
the class ThirdPartyClass* definition above, the header files for
ThirdPartyClass
can be hidden away in your implementation.

If you need all the interfaces of ThirdPartyClass, then you'll have to
repeat them in MyClass and forward the work onto the _thirdPartyClass
member.

MyClass::doFoo()
{
_thirdPartyClass->doFoo();

}

Hope that helps.

dave
 
K

Karthik Kumar

Sim said:
This is the problem:

I have to inherit a third party class file in my library. If I
directly do it, I will have to ship the third party header files to my
customers as well. I do not want to ship the third party header files
to my customers. What is the most elegant way to handle this problem.

For example:
// MyClass.h

#include "ThirdPartyClass.h"

class MyClass : public ThirdPartyClass
{
};

I would prefer keeping my class definitions in the header files.

Thanks
Sim

Not Possible.

Case A:
If you are going to have a third party library in your
*implementation*, then you may not need to
distribute the headers .


MyClass.h:

class MyClass {

};


MyClass.cc :

#include "ThirdPartyClass.h"

// MyClass definition proceeds


Here it is ok, not to distribute the header files
of ThirdPartyClass , but you would still need the library, (the
binaries) though.



Case B:
But if you have it as part of your declaration you have
to redistribute the same.


#include "ThirdPartyClass.h"

class MyClass : public ThirdPartyClass
{
};

You have to redistribte ThirdPartyClass (How else
would the compiler resolve the access privileges of fields and
methods).
Those information are not archived in the library binaries ( at least
not necessary to be standards-compliant).

--
Karthik.
------------ And now a word from our sponsor ------------------
For a quality usenet news server, try DNEWS, easy to install,
fast, efficient and reliable. For home servers or carrier class
installations with millions of users it will allow you to grow!
---- See http://netwinsite.com/sponsor/sponsor_dnews.htm ----
 
D

David Hilsee

Dave Townsend said:
Do you really need to inherit from the thirdparty ? If you don't then you
can compose the thirdparty class as a member variable in your class. This
is the Design Patterns book "prefer composition over inheritance" idiom.

class myclass : public .......whatever bases you need.....
{

MyClass( .....)
{
_thirdPartyClass = new ThirdPartyClass();
}
private:
class ThirdPartyClass* _thirdPartyClass

};

Since the member is a pointer, you can get away with a forward
declaration,or
the class ThirdPartyClass* definition above, the header files for
ThirdPartyClass
can be hidden away in your implementation.

If you need all the interfaces of ThirdPartyClass, then you'll have to
repeat them in MyClass and forward the work onto the _thirdPartyClass
member.

MyClass::doFoo()
{
_thirdPartyClass->doFoo();

}

Hope that helps.

This sounds like the way to go. Personally, when I do this, I just use the
pimpl idiom and don't bother providing incomplete declarations for classes
that are used in the implementation. If you do that, then you don't have to
modify the header when you add another "private" member variable. It can
also simplify management of the members (one dynamic allocation versus,
potentially, many).
 
D

Dave Townsend

This sounds like the way to go. Personally, when I do this, I just use the
pimpl idiom and don't bother providing incomplete declarations for classes
that are used in the implementation. If you do that, then you don't have to
modify the header when you add another "private" member variable. It can
also simplify management of the members (one dynamic allocation versus,
potentially, many).

David, don't make me hunt for my Coplien book - the pimpl idiom - I don't
remember
the details ? Is this where you have a member which is a pointer to a
virtual base class
which has the same interface as the class you are implementing....? I
guess that would
hermitally seal up any third party classes from even the most enquiring
minds.

for example:
class Foo
{
// some abstract class.
};
class FooBar : public Foo
{
Foo* _impl;

};

/// tucked away in a header file somewhere

class FooImpl : public Foo
{
// .....
ThirdPartyClass1* _thirdparty1;
ThirdPartyClass2* _thirdparty2;

// .....etc
};
 
D

David Hilsee

Dave Townsend said:
have

David, don't make me hunt for my Coplien book - the pimpl idiom - I don't
remember
the details ? Is this where you have a member which is a pointer to a
virtual base class
which has the same interface as the class you are implementing....? I
guess that would
hermitally seal up any third party classes from even the most enquiring
minds.

for example:
class Foo
{
// some abstract class.
};
class FooBar : public Foo
{
Foo* _impl;

};

/// tucked away in a header file somewhere

class FooImpl : public Foo
{
// .....
ThirdPartyClass1* _thirdparty1;
ThirdPartyClass2* _thirdparty2;

// .....etc
};

Google to the rescue! The first link it provides
(http://www.gotw.ca/gotw/024.htm) is quite good. There's no need for the
inheritance relationship. It usually looks something like this:

// header
class FooImpl;
class Foo {
// ...
private:
FooImpl * pImpl_;
};

// implementation
class FooImpl {
// members that were private in Foo are here
};

// definition of member functions of Foo are placed here
 
M

ma740988

David Hilsee said:
Google to the rescue! The first link it provides
(http://www.gotw.ca/gotw/024.htm) is quite good. There's no need for the
inheritance relationship. It usually looks something like this:

// header
class FooImpl;
class Foo {
// ...
private:
FooImpl * pImpl_;
};

// implementation
class FooImpl {
// members that were private in Foo are here
};

// definition of member functions of Foo are placed here

Perhaps you could shed light on - I presume - my confusion with
regard to the the use of - what the article calls - 'back pointer'.
So now, consider

//////////////////////////////
// bar.h
#ifndef BAR_H
#define BAR_H
# include <memory>
class FOO;
class BAR
{
public:
BAR();
~BAR();
private:
FOO* foo;
};
#endif


//////////////////////////////
//bar.cpp
# include "foo.h"
# include "bar.h"

BAR::BAR() : foo( new FOO(this) ) { } // (1)
BAR::~BAR() { delete foo; }


//////////////////////////////
//foo.h
#ifndef FOO_H
#define FOO_H

# include <memory>
# include "bar.h"
class BAR;
class FOO
{
public:
FOO(BAR* bar_);
~FOO();
private:
BAR* bar;
};

//////////////////////////////
//foo.cpp
# include "foo.h"
# include <iostream>

FOO::FOO(BAR* bar_) : bar(bar_) {}
FOO::~FOO() { }

//////////////////////////////
//main.cpp

# include<iostream>
# include "foo.h"
# include "bar.h"

int main()
{
BAR *ptrBar = new BAR;
delete ptrBar;
return 0;
}

Per line "(1)" above.
Isn't it safe to state that the 'foo' object is created using a an
'incomplete' bar object?
Is there alternative when dealing with a 'scenario' such as this?
 
D

David Hilsee

Perhaps you could shed light on - I presume - my confusion with
regard to the the use of - what the article calls - 'back pointer'.
So now, consider

//////////////////////////////
// bar.h
#ifndef BAR_H
#define BAR_H
# include <memory>
class FOO;
class BAR
{
public:
BAR();
~BAR();
private:
FOO* foo;
};
#endif

Copy constructor and assignment operator omitted for brevity, right? ;-)
//////////////////////////////
//bar.cpp
# include "foo.h"
# include "bar.h"

BAR::BAR() : foo( new FOO(this) ) { } // (1)
BAR::~BAR() { delete foo; }


//////////////////////////////
//foo.h
#ifndef FOO_H
#define FOO_H

# include <memory>
# include "bar.h"
class BAR;
class FOO
{
public:
FOO(BAR* bar_);
~FOO();
private:
BAR* bar;
};

//////////////////////////////
//foo.cpp
# include "foo.h"
# include <iostream>

FOO::FOO(BAR* bar_) : bar(bar_) {}
FOO::~FOO() { }

//////////////////////////////
//main.cpp

# include<iostream>
# include "foo.h"
# include "bar.h"

int main()
{
BAR *ptrBar = new BAR;
delete ptrBar;
return 0;
}

Per line "(1)" above.
Isn't it safe to state that the 'foo' object is created using a an
'incomplete' bar object?

Well, I think it's best to say that FOO's constructor is passed a pointer to
a BAR object whose constructor has not finished executing. In those cases,
it is best if FOO does not access the object, because the object may be in
an inconsistent state, and all sorts of nastiness can happen if you're not
careful. If this were the pimpl idiom, then it looks like FOO is BAR's
implementation class, and FOO shouldn't have any reason to do anything with
the instance of BAR.
Is there alternative when dealing with a 'scenario' such as this?

There's nothing wrong with the above code. I think Sutter's complaints
about the back pointer concerned efficiency ("extra level of indirection").
I don't see much of a problem with this:

// Typical pimpl header w/forward declaration and pImpl_ member
#include "Foo.h"

struct FooImpl {
int usedToBePrivate;
// can't depend on "this" for access to Foo, so take an argument
void usedToBePrivateToo(Foo * self);
};

void Foo::publicMember(){
// ...
pImpl_->usedToBePrivateToo(this);
}

The fact that he referred to the back pointer as "self_" instead of "self"
makes me wonder if the back pointer was a member of the implementation
class. I wouldn't bother doing that. That would just make the
implementation object larger for (IMHO) little benefit. I suppose it could
be argued that it's more readable if it's a member.
 
O

Old Wolf

Perhaps you could shed light on - I presume - my confusion with
regard to the the use of - what the article calls - 'back pointer'.
So now, consider

//////////////////////////////
// bar.h
#ifndef BAR_H
#define BAR_H
# include <memory>
class FOO;
class BAR
{
public:
BAR();
~BAR();
private:
FOO* foo;
};
#endif


//////////////////////////////
//bar.cpp
# include "foo.h"
# include "bar.h"

BAR::BAR() : foo( new FOO(this) ) { } // (1)
BAR::~BAR() { delete foo; }

//////////////////////////////
//main.cpp

# include<iostream>
# include "foo.h"
# include "bar.h"

int main()
{
BAR *ptrBar = new BAR;
delete ptrBar;
return 0;
}

Per line "(1)" above.
Isn't it safe to state that the 'foo' object is created using a an
'incomplete' bar object?

No, it's created using a pointer. The 'this' pointer is valid
in the constructor's initializer list, as are all of the object's
member variables declared before the one you're initializing,
and all the non-virtual functions. (Typically, FOO's constructor
and destructor won't dereference the pointer it's created with).
Is there alternative when dealing with a 'scenario' such as this?

None necessary, your code looks fine to me.

However if the constructor throws an exception then the destructor
will never be called and foo won't be deleted. So you should either
use a std::auto_ptr for foo, or ensure that the constructor
(and any initializers after 'foo') cannot throw.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,432
Messages
2,571,680
Members
48,796
Latest member
Greg L.

Latest Threads

Top