473,473 Members | 2,125 Online
Bytes | Software Development & Data Engineering Community
Create Post

Home Posts Topics Members FAQ

Restricting base class visibility

I have a system that looks like this:

class AbstractBase { /* ... */ };
template <class T> class Impl : public AbstractBase { /* ... */ };
// ...
Impl<int> i;
Impl<float> f;
std::vector<AbstractBase*> vec;
vec.push_back(&i);
vec.push_back(&f);
// ...

It works. However, at the moment, class AbstractBase has public
visibility - anyone can subclass it. Ideally, the only subclasses of
AbstractBase should be instantiations of Impl. Impl, on the other hand,
can (and should) be instantiable by anyone. Is it possible for me to
somehow hide AbstractBase to restrict what classes can subclass it?

Thanks,
Rennie deGraaf
Jan 5 '06 #1
12 1752
Rennie deGraaf wrote:
I have a system that looks like this:

class AbstractBase { /* ... */ };
template <class T> class Impl : public AbstractBase { /* ... */ };
// ...
Impl<int> i;
Impl<float> f;
std::vector<AbstractBase*> vec;
vec.push_back(&i);
vec.push_back(&f);
// ...

It works. However, at the moment, class AbstractBase has public
visibility - anyone can subclass it. Ideally, the only subclasses of
AbstractBase should be instantiations of Impl. Impl, on the other hand,
can (and should) be instantiable by anyone. Is it possible for me to
somehow hide AbstractBase to restrict what classes can subclass it?

You can make the constructor of AbstractBase private, then make Impl a
friend of AbstractBase. That way, only Impl knows how to construct the
AbstractBase sub-object.

But I'm curious, why restrict the use of AbstractBase in this way?

Hope this helps,
-shez-

Jan 5 '06 #2

Rennie deGraaf wrote:
I have a system that looks like this:

class AbstractBase { /* ... */ };
template <class T> class Impl : public AbstractBase { /* ... */ };
// ...
Impl<int> i;
Impl<float> f;
std::vector<AbstractBase*> vec;
vec.push_back(&i);
vec.push_back(&f);
// ...

It works. However, at the moment, class AbstractBase has public
visibility - anyone can subclass it. Ideally, the only subclasses of
AbstractBase should be instantiations of Impl. Impl, on the other hand,
can (and should) be instantiable by anyone. Is it possible for me to
somehow hide AbstractBase to restrict what classes can subclass it?


The obvious question to ask is why are AbstractBase and Impl distinct
classes to start with, if AbstractBase is meant to have only a single
subclass.

Greg

Jan 5 '06 #3
Greg wrote:
The obvious question to ask is why are AbstractBase and Impl distinct
classes to start with, if AbstractBase is meant to have only a single
subclass.
From the OP's code, it looks like he wants to create a vector

containing heterogenous objects. The problem with his approach is that
the <AbstractBase*> parameter for vector does not preserve value
semantics. A better approach would be to use something boost::any or
boost::variant, where value-semantics are maintained.

-shez-

Jan 5 '06 #4
Greg wrote:
Rennie deGraaf wrote:
I have a system that looks like this:

class AbstractBase { /* ... */ };
template <class T> class Impl : public AbstractBase { /* ... */ };
// ...
Impl<int> i;
Impl<float> f;
std::vector<AbstractBase*> vec;
vec.push_back(&i);
vec.push_back(&f);
// ...

It works. However, at the moment, class AbstractBase has public
visibility - anyone can subclass it. Ideally, the only subclasses of
AbstractBase should be instantiations of Impl. Impl, on the other hand,
can (and should) be instantiable by anyone. Is it possible for me to
somehow hide AbstractBase to restrict what classes can subclass it?

The obvious question to ask is why are AbstractBase and Impl distinct
classes to start with, if AbstractBase is meant to have only a single
subclass.

Greg


What I need is an STL container (I'm actually using an std::map, but an
std::vector was simpler for the example) containing a bunch of different
instantiations of Impl. In other words, a container can can store an
Impl<int> and an Impl<string>, but not an int or a string. AFAIK, C++
doesn't define references or pointers to templates, only to template
instantiations, so I need to refer to objects of Impl<int> and
Impl<string> through a base class.

Since the STL doesn't seem to play nicely with polymorphic types, I have
to store pointers to my objects, rather than the objects themselves, and
handle allocation myself. It's a pain, but I don't know any better
ways. I'm open to suggestions, if you have them.

Rennie
Jan 5 '06 #5
Rennie deGraaf wrote:

What I need is an STL container (I'm actually using an std::map, but an
std::vector was simpler for the example) containing a bunch of different
instantiations of Impl. In other words, a container can can store an
Impl<int> and an Impl<string>, but not an int or a string. AFAIK, C++
doesn't define references or pointers to templates, only to template
instantiations, so I need to refer to objects of Impl<int> and
Impl<string> through a base class.

Since the STL doesn't seem to play nicely with polymorphic types, I have
to store pointers to my objects, rather than the objects themselves, and
handle allocation myself. It's a pain, but I don't know any better
ways. I'm open to suggestions, if you have them.


As shezan suggested, you can solve this by having private Constructor
in AbstractBase

#include <vector>

class AbstractBase {
protected:
virtual ~AbstractBase() { }
private:
AbstractBase(){ }
template<class T> friend class Impl;

};

template <class T> class Impl : public AbstractBase {
T i;
};
class Zoo : public AbstractBase {
};
// Zoo cannot be instantiated because constructor of base class is
private.

int main()
{
Impl<int> i;
Impl<float> f;
// Zoo z; // not allowed

std::vector<AbstractBase*> v;
v.push_back(&i);
v.push_back(&f);

// v.push_back(&z); // Error.

}

Jan 5 '06 #6
Rennie deGraaf wrote:
Since the STL doesn't seem to play nicely with polymorphic types, I have
to store pointers to my objects, rather than the objects themselves, and
handle allocation myself. It's a pain, but I don't know any better
ways. I'm open to suggestions, if you have them.

I guess I should rephrase my original question so: What virtual
functions are you going to have in 'AbstractBase'? If there are no
virtual functions, there should be no need for inheritance. If there
*are* virtual functions, when why make 'AbstractBase' completely
hidden?

I suggested 'boost::any' earlier, but if you want to restrict your
container to only contain 'Impl' objects, then it is reasonably
straightforward to adapt 'boost::any' to restrict only 'Impl' types.
Something like:
class AnyImpl {
// PRIVATE DATA MEMBERS
boost::any d_any;

public:
template <typename TYPE>
AnyImpl(const Impl<TYPE>& value) : d_any(value) { }

template <typename TYPE>
AnyImpl& operator=(const Impl<TYPE>& value) { d_any = value; }
};
Now you can create vector<AnyImpl> or map<AnyImpl, AnyImpl>.
Hope this helps,
-shez-

Jan 5 '06 #7
Shezan Baig wrote:
Rennie deGraaf wrote:
I have a system that looks like this:

class AbstractBase { /* ... */ };
template <class T> class Impl : public AbstractBase { /* ... */ };
// ...
Impl<int> i;
Impl<float> f;
std::vector<AbstractBase*> vec;
vec.push_back(&i);
vec.push_back(&f);
// ...

It works. However, at the moment, class AbstractBase has public
visibility - anyone can subclass it. Ideally, the only subclasses of
AbstractBase should be instantiations of Impl. Impl, on the other hand,
can (and should) be instantiable by anyone. Is it possible for me to
somehow hide AbstractBase to restrict what classes can subclass it?

You can make the constructor of AbstractBase private, then make Impl a
friend of AbstractBase. That way, only Impl knows how to construct the
AbstractBase sub-object.


Of course, doing this would make *all* of AbstractBase's private methods
and data accessible to Impl. Is it possible to only make Impl's
constructor a friend to AbstractBase? I can't find anything on the
subject, and can't figure out any syntax that compiles.
But I'm curious, why restrict the use of AbstractBase in this way?


My code assumes that all objects that it pulls out of vec are
instantiations of Impl. If someome subclasses AbstractBase with
something else and gets it into vec, then my code with throw an
exception with an error message that assumes a completely different
problem. My code can't tell the difference between a specialization of
Impl that it doesn't know about and something that isn't an Impl at all.

Also, I intend people using my system to write specializations of Impl,
and don't want to make it possible for people to get confused and try to
subclass AbstractBase instead. If I make Impl a friend of AbstractBase
and make AbstractBase's constructor private, then this can't happen, but
then people might mess around with AbstractBase's private data and
totally s*crew up the system. Neither is a critical problem (unless
someome finds a way to make a buffer overflow or something out of it),
but I'd rather have neither, and I'm not sure which is worse.

Rennie
Jan 5 '06 #8
> Rennie deGraaf" <ca.ucalgary.cpsc@degraaf> wrote:
Rennie deGraaf wrote:
I have a system that looks like this:

class AbstractBase { /* ... */ };
template <class T> class Impl : public AbstractBase { /* ... */ };
// ...
Impl<int> i;
Impl<float> f;
std::vector<AbstractBase*> vec;
vec.push_back(&i);
vec.push_back(&f);
// ...

It works. However, at the moment, class AbstractBase has public
visibility - anyone can subclass it. Ideally, the only subclasses of
AbstractBase should be instantiations of Impl. Impl, on the other hand,
can (and should) be instantiable by anyone. Is it possible for me to
somehow hide AbstractBase to restrict what classes can subclass it?


What I need is an STL container (I'm actually using an std::map, but an
std::vector was simpler for the example) containing a bunch of different
instantiations of Impl. In other words, a container can can store an
Impl<int> and an Impl<string>, but not an int or a string. AFAIK, C++
doesn't define references or pointers to templates, only to template
instantiations, so I need to refer to objects of Impl<int> and
Impl<string> through a base class.

Since the STL doesn't seem to play nicely with polymorphic types, I have
to store pointers to my objects, rather than the objects themselves, and
handle allocation myself. It's a pain, but I don't know any better
ways. I'm open to suggestions, if you have them.


I would suggest looking into a discriminated union or similar, variant type
(such as Boost's variant) as an alternative solution. I think either of
those approaches would involve less "housekeeping" chores, require fewer
lines code, and overall be simply easier to manage than the implementation
described above. The benefit of a union or variant class derives from having
just one class do the work currently slated for one base class and several,
derived classes - in short - an entire class hierarchy.

Greg

Jan 5 '06 #9

"Neelesh Bodas" <ne***********@gmail.com> skrev i meddelandet
news:11********************@g14g2000cwa.googlegrou ps.com...
Rennie deGraaf wrote:

What I need is an STL container (I'm actually using an std::map,
but an
std::vector was simpler for the example) containing a bunch of
different
instantiations of Impl. In other words, a container can can store
an
Impl<int> and an Impl<string>, but not an int or a string. AFAIK,
C++
doesn't define references or pointers to templates, only to
template
instantiations, so I need to refer to objects of Impl<int> and
Impl<string> through a base class.

Since the STL doesn't seem to play nicely with polymorphic types, I
have
to store pointers to my objects, rather than the objects
themselves, and
handle allocation myself. It's a pain, but I don't know any better
ways. I'm open to suggestions, if you have them.
As shezan suggested, you can solve this by having private
Constructor
in AbstractBase

#include <vector>

class AbstractBase {
protected:
virtual ~AbstractBase() { }
private:
AbstractBase(){ }
template<class T> friend class Impl;

};

template <class T> class Impl : public AbstractBase {
T i;
};
class Zoo : public AbstractBase {
};
// Zoo cannot be instantiated because constructor of base class is
private.


But it doesn't stop the pervasive intruder!

struct ooZ {};

template<>
class Impl<ooZ> : public AbstractBase {
// whatever Zoo wants to do!
};

typedef Impl<ooZ> Zoo;


int main()
{
Impl<int> i;
Impl<float> f;
// Zoo z; // not allowed
Now it is allowed!

std::vector<AbstractBase*> v;
v.push_back(&i);
v.push_back(&f);

// v.push_back(&z); // Error.

}

Jan 10 '06 #10
Rennie deGraaf wrote:
I have a system that looks like this:

class AbstractBase { /* ... */ };
template <class T> class Impl : public AbstractBase { /* ... */ };
// ...
Impl<int> i;
Impl<float> f;
std::vector<AbstractBase*> vec;
vec.push_back(&i);
vec.push_back(&f);
// ...

It works. However, at the moment, class AbstractBase has public
visibility - anyone can subclass it. Ideally, the only subclasses of
AbstractBase should be instantiations of Impl. Impl, on the other hand,
can (and should) be instantiable by anyone. Is it possible for me to
somehow hide AbstractBase to restrict what classes can subclass it?

Thanks,
Rennie deGraaf


In addition to the comments you've already received and depending on
what direction your design takes, you might be interested in this
article on the Attorney-Client idiom:

http://www.cuj.com/documents/s=8188/...601bolton.html

Cheers! --M

Jan 10 '06 #11

Rennie deGraaf wrote:
Shezan Baig wrote:
You can make the constructor of AbstractBase private, then make Impl a
friend of AbstractBase. That way, only Impl knows how to construct the
AbstractBase sub-object.


Of course, doing this would make *all* of AbstractBase's private methods
and data accessible to Impl. Is it possible to only make Impl's
constructor a friend to AbstractBase? I can't find anything on the
subject, and can't figure out any syntax that compiles.


That would not be the safest thing to do as anyone can specialise their
Impl template.

There is a way to be restrictive this way.

Have another class that implements all the private parts of
AbstractBase, make AbstractBase a friend of that class and then make
Impl a friend of AbstractBase.Then Impl will only have access to the
constructor of AbstractBase but not the remainder as friendship isn't
transitive.

I don't know your full model but if it involves casting down the
hierarchy later on then it is probably wrong. The only times I use
casting is when I am loading objects from a library and have to check
that the type I have loaded is the type I expected to receive. It also
happens to fit in well with a generic loading model that can store in
one collection lots of different factory types.

Jan 11 '06 #12
Earl Purple wrote:
Rennie deGraaf wrote:
Shezan Baig wrote:
You can make the constructor of AbstractBase private, then make Impl a
friend of AbstractBase. That way, only Impl knows how to construct the
AbstractBase sub-object.


Of course, doing this would make *all* of AbstractBase's private methods
and data accessible to Impl. Is it possible to only make Impl's
constructor a friend to AbstractBase? I can't find anything on the
subject, and can't figure out any syntax that compiles.


That would not be the safest thing to do as anyone can specialise their
Impl template.

There is a way to be restrictive this way.

Have another class that implements all the private parts of
AbstractBase, make AbstractBase a friend of that class and then make
Impl a friend of AbstractBase.Then Impl will only have access to the
constructor of AbstractBase but not the remainder as friendship isn't
transitive.


[snip]

This is the Attorney-Client idiom described in the article I cited in
my first post in this thread.

Cheers! --M

Jan 11 '06 #13

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

5
by: Dan =o\) | last post by:
given this brief scenario, is this possible somehow? class A { public SomeMethod() { } }
1
by: mdb | last post by:
I'm trying to restrict the characters that are valid in a textBox, so I derived from System.Windows.Forms.TextBox, and overrode WndProc, catching the key up/down messages... Everything works...
2
by: clintonG | last post by:
I've created a base class that inherits from System.Web.UI.Page. I've been using Page_PreInit in the base class to change Themes. I'm using MasterPages and need a bunch of code in each content...
1
by: Piper707 | last post by:
Hi, I'd like to know if there are any more ways of restricting an XML document to having only non-empty tags (containing Strings). I can think of 2 ways: 1) <xs:simpleType name="tagName">
5
by: EqDev | last post by:
I have a class that is a control derived from UserControl. I want to use serialization and deserialization with this calss but I get an exception "Cannot serialize member...
4
by: Colin Desmond | last post by:
Is it possible to write an attribute that changes the visibility of a class (public/private) etc based on some pre-compiler define symbol? We're writing some classes which will be called by an...
11
by: Darren.Ratcliffe | last post by:
Hi guys Posted what was probably a rather confusing post about this the other day, so I am going to have another go and see if I can make more sense. This sis purely a I've got a base class...
2
by: WittyGuy | last post by:
Hi My class looks something like this: class Base { public: Base () {} ~Base () {} // No virtual dtor in the base class private: };
10
by: Janis Papanagnou | last post by:
The task seems simple but I am not sure whether this is possible or even the right way to look at it... I have <td class="X"elements where "X" is a placeholder for class names "A", "B", etc. ...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
1
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
1
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...
0
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The...
0
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
0
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated ...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.