2

Suppose there are two classes like so

class Locator
{
public:
// this goes to the specified latitide and longitude
bool GoToLocation(long lat, long longtd);
};

class HouseLocator : private Locator
{
public:
// this internally uses GoToLocation() after fetching the location from address map
bool GoToAddress(char *p);
}

I make private inheritance to block GoToLocation() on HouseLocator because it doesn't make sense there and to force people to use the proper interface.

Now my question is, how can I prevent this kind of casting?

HouseLocator *phl = new HouseLocator;
Locator *pl = (Locator*)phl;
pl->GoToLocation(10, 10);

Should I just document not to do this and leave the rest to the user, I mean, if he makes wrong cast, its his problem?

Karl
  • 21
  • 2
  • 3
    You can't prevent it. If you don't want it to work, and it doesn't make sense, why don't you have HouseLocator contain a Locator, rather than inherit from it? – forsvarir Apr 15 '11 at 08:42
  • No matter what you do, people can force their way around it using e.g. platform-specific tricks. Using private inheritance like you do is enough - you clearly indicate that the `Locator` interface should not be used, if the user wants to break stuff it's not your problem. – Erik Apr 15 '11 at 08:43
  • Look at the answser at http://stackoverflow.com/questions/5650790/compiler-switch-to-disable-const-cast-sematics-in-c-style-casts/5651174#comment-6444754 for some GCC options to help you out. – edA-qa mort-ora-y Apr 15 '11 at 08:44
  • Ugly solution number XXX... change the base class so that GoToLocation is virtual and override it in HouseLocator to throw a NotSupportedException.... – forsvarir Apr 15 '11 at 08:48
  • @forsvarir : Ugh.. A runtime error for a compile-time problem? At that point, why use a statically typed language in the first place? – ildjarn Apr 15 '11 at 08:50
  • @ildjarn: I never said it was pretty! Saddly, I've had it used on me in the past where the class designer was trying to be overly strict about the way it could be used... – forsvarir Apr 15 '11 at 08:53
  • @forsvarir: actually a C cast should work even if you use containment... – Matthieu M. Apr 15 '11 at 09:35
  • @Karl: you'd better pass a `std::string const&` that a `char*` for the address. And you're not forced to allocated with `new` to use polymorphic behavior: `HouseLocator hl; Locator* l = (Locator*)(&hl);` works as well, without memory leaks. – Matthieu M. Apr 15 '11 at 09:36
  • @Matthieu M.: I don't see how. class HouseLocator { int _someVar; Locator _locator;}; You'd be making some serious assumptions about structure and memory location if you were casting an instance of (HouseLocator*) to (Locator*) and still expecting it to work. Perhaps we have some confusion about what I meant by containment? – forsvarir Apr 15 '11 at 10:04
  • @forsvarir: you already make serious assumptions by using a C-cast, if I were to change it to `class HouseLocator: private House, private Locator` then you'd be equally screwed up. – Matthieu M. Apr 15 '11 at 11:01

6 Answers6

6

Use composition instead of inheritance:

class Locator
{
public:
    bool GoToLocation(long lat, long longtd);
};

class HouseLocator
{
    Locator locator_;
public:
    // internally uses locator_.GoToLocation()
    bool GoToAddress(char *p);
};

If that's not practical for some reason, then using private inheritance as you already are is your best bet -- if the user casts a HouseLocator* to a Locator* they're invoking undefined behavior, and that's their problem, not yours.

ildjarn
  • 62,044
  • 9
  • 127
  • 211
2

If you can change the base class, you can make the function protected instead of public.

Otherwise there isn't much you can do, except telling people not to do this.

Bo Persson
  • 90,663
  • 31
  • 146
  • 203
1

You can't. The C cast include the reinterpret_cast functionality and you can't prevent reinterpret_casting between any two data pointer types.

Note that that cast will not do the adjustments needed in some cases of multiple inheritance and thus may fail to achieve its intended result. (static_cast will do the adjustements, but will check accessibility).

AProgrammer
  • 51,233
  • 8
  • 91
  • 143
1

This looks as though HouseLocator probably shouldn't derive from Locator. From the limited context, you probably want something that uses locator (i.e., it's composed as a private member variable).

Private inheritance is almost exclusively used as a composition device, when you cant compose directly (because you also need to specialize the class).

Inheritance is generally used when you want a heterogeneous collection of some type and you want to treat them all the same (or in similar situations). If youre using the derived class in a way that requires you to know the derived type, inheritance is actually usually harming your design because its the tightest form of coupling (must be constructed and together, cannot be rebound).

Cechner
  • 849
  • 7
  • 19
0

Not worth trying to prevent it IMHO. User can anyways do Locator* p = new Locator(); p->GoToLocation(10,10);

Naveen
  • 74,600
  • 47
  • 176
  • 233
0

You may also conversion operator

operator Locator() const;

that raises exception in HouseLocator class. But this will not prevent the conversion by reinterpret_cast<>. Nothing can prevent it.

Jurlie
  • 1,014
  • 10
  • 27