-
Polymorphism violating private access modifier
I'm surprised I haven't encountered this yet (or perhaps I have but somehow didn't notice):
Code:
#include <iostream>
#include <vector>
class Base
{
public:
virtual bool Is_Mouse_Over() const = 0;
};
class A : public Base
{
public:
virtual bool Is_Mouse_Over() const
{
std::cout << "A::Is_Mouse_Over" << std::endl;
return true;
}
};
class B : public Base
{
private:
virtual bool Is_Mouse_Over() const
{
std::cout << "B::Is_Mouse_Over" << std::endl;
return true;
}
};
int main()
{
std::vector<Base*> objects;
objects.push_back(new A());
objects.push_back(new B());
objects[0]->Is_Mouse_Over();
objects[1]->Is_Mouse_Over();
return 0;
}
Prints out:
Quote:
A::Is_Mouse_Over
B::Is_Mouse_Over
Doesn't this violate the private access modifier somehow?
Cheers.
-
Re: Polymorphism violating private access modifier
hmm... but why would one override a method with public access to have private access in the first place?
-
Re: Polymorphism violating private access modifier
Quote:
Originally Posted by
laserlight
hmm... but why would one override a method with public access to have private access in the first place?
Because they suck at designing inheritance hierarchies. ;)
I have a GUI_Object base class and decided recently that I needed my Text class to derive from it. However, the Text class shouldn't have some functions that the GUI_Object class declares.
-
Re: Polymorphism violating private access modifier
Quote:
Originally Posted by Mybowlcut
I have a GUI_Object base class and decided recently that I needed my Text class to derive from it. However, the Text class shouldn't have some functions that the GUI_Object class declares.
If the Text class should not have the public interface of the GUI_Object class in its entirety, then a Text object is not a GUI_Object, so you should not use public inheritance. Maybe you should use composition or private inheritance instead.
-
Re: Polymorphism violating private access modifier
It certainly is an interesting observation, I hadn't encountered this one. Thanks for that.
I am not saying what happened in this case is correct,
but I am explaining why it happened. (correct me if i am wrong):
--------------------------------------------------------------------------------------------------------------------
This happens because of late binding. (Binding is done at runtime for virtual functions).
So at compile time the compiler doesn't know the value contained in objects[0] and objects[1].
The compiler simply assumes that it objects[0] and objects[1] point to an object of the class Base.
Since the class Base does have the function as public, it lets it through.
Just to check this, you could make the following function private:
Code:
Base :: Is_Mouse_Over() //Make this function private and all Is_Mouse_Over() functions
//of the inherited classes would be inaccessible
If you make it private, then all the functions would be inaccessible. This is bcuz at compile time, the compiler assumes the objects[0] and objects[1] point to object of the class Base.
Again pls correct me if I am wrong.
-
Re: Polymorphism violating private access modifier
Hi Mybowlcut, haven't seen you in a while
Quote:
Originally Posted by Mybowlcut
I'm surprised I haven't encountered this yet
that's probablly because we wouldn't normally overide a public method with private access xD
I'm not sure if access modifier inside the class also restricts the call mechanism in the vtable like it does for the calls made outside
I suppose, if any does restricts, it's the access modifier on the deriviation list.
-
Re: Polymorphism violating private access modifier
Quote:
Originally Posted by
laserlight
If the Text class should not have the public interface of the GUI_Object class in its entirety, then a Text object is not a GUI_Object, so you should not use public inheritance. Maybe you should use composition or private inheritance instead.
The real reason that it came about was that I was creating a GUI builder, and I needed to have a function that could create an object that derived from GUI_Object based on a string parameter and return the object as a shared_ptr<GUI_Object>.
Perhaps private inheritance is what I want if I want to be able to do what I mentioned above...
Edit: Muthuveerappan, that's why I thought it was happening too.
Hi potatoCode. :)
-
Re: Polymorphism violating private access modifier
Hello there Mybowlcut :)
as awlays, it'd be nice to see if someone could confirm what the Standard has to say on this.
-
Re: Polymorphism violating private access modifier
Quote:
Originally Posted by Mybowlcut
The real reason that it came about was that I was creating a GUI builder, and I needed to have a function that could create an object that derived from GUI_Object based on a string parameter and return the object as a shared_ptr<GUI_Object>.
So, what is wrong with allowing Text to have the full public interface of GUI_Object?
Quote:
Originally Posted by Mybowlcut
Perhaps private inheritance is what I want if I want to be able to do what I mentioned above...
No, it would not: generally, private inheritance is used to inherit an implementation, not to allow for polymorphism.
-
Re: Polymorphism violating private access modifier
Quote:
Originally Posted by
laserlight
So, what is wrong with allowing Text to have the full public interface of GUI_Object?
No, it would not: generally, private inheritance is used to inherit an implementation, not to allow for polymorphism.
Here is my GUI_Object class:
Code:
class GUI_Object;
typedef boost::shared_ptr<GUI_Object> gui_object_ptr;
typedef boost::weak_ptr<GUI_Object> weak_gui_object_ptr;
class Screen_Event;
// The base of all GUI objects.
class GUI_Object
: public Named
, public Renderable
, public Event_Updateable
, public boost::enable_shared_from_this<GUI_Object>
{
public:
GUI_Object();
GUI_Object(const std::string& name, weak_gui_object_ptr parent,
bool visible, const PointI& position, const PointI& size, bool blocks, ushort depth);
virtual ~GUI_Object() = 0;
GUI_Object& operator=(const GUI_Object& rhs);
virtual bool Is_Visible() const;
virtual void Set_Visible(bool visible);
virtual const PointI Get_Position() const;
// Returns the absolute position of this object if it has a parent.
// If there is no parent, return value is equal to Get_Position().
virtual PointI Get_Absolute_Position() const;
virtual void Set_Position(const PointI& position);
virtual const PointI Get_Size() const;
virtual void Set_Size(const PointI& size);
ushort Get_Depth() const;
virtual void Set_Depth(ushort depth);
bool Blocks() const;
bool Has_Parent() const;
weak_gui_object_ptr Get_Parent();
void Set_Parent(weak_gui_object_ptr parent);
// If reading a GUI_Object from xml, we need a way to determine it's parent (if any).
// The easiest way to do this is from within code, from an already constructed object.
virtual void Read(ticpp::Element* element, weak_gui_object_ptr parent = weak_gui_object_ptr()) = 0;
// Whilst most classes derived from GUI_Object do not need to be written,
// there are some that do, thus all must be able to.
virtual void Write(ticpp::Element* element) const = 0;
virtual bool Is_Mouse_Over(const PointI& mouse) const = 0;
virtual bool Blocks_Mouse(const PointI& mouse, ushort source_depth) const;
// Returns true if this has the current focus.
virtual bool Has_Focus() const = 0;
protected:
bool visible;
PointI position;
PointI size;
bool blocks;
ushort depth;
weak_gui_object_ptr parent;
};
Here is my Text class:
Code:
class Text
: public GUI_Object
{
public:
Text();
Text(const std::string& text, const std::string& font_fn, const PointI& position,
int font_size, const SDL_Colour& colour, QUALITY quality, Uint8 alpha, ushort depth);
Text(const Text& rhs);
virtual ~Text();
Text& operator=(const Text& rhs);
virtual void Read(ticpp::Element* element, weak_gui_object_ptr parent = weak_gui_object_ptr());
virtual void Write(ticpp::Element* element) const;
using Renderable::Render;
virtual void Render(SDL_Renderer& renderer);
virtual void Render(SDL_Renderer& renderer, const PointI& position);
virtual bool Is_Mouse_Over(const PointI& mouse) const;
const std::string& Get_Text() const;
void Set_Text(const std::string& text);
template<typename T>
void Set_Text(const T& t)
{
Set_Text(Conversions::to_string(t));
}
void Clear_Text();
void Centre(const PointI& point);
void Centre(int x_or_y, Direction::AXIS axis);
void Centre(const PointI& position, const PointI& size);
void Centre(int x_or_y, int w_or_h, Direction::AXIS axis);
TTF_Font* Get_Font();
const int Get_Font_Height() const;
// Returns the surface size of this text.
const PointI Get_Surface_Size() const;
// Returns the surface size of text using this font.
const PointI Get_Surface_Size(const std::string& text) const;
// Returns the surface width of text using font.
static const PointI Get_Surface_Size(TTF_Font* font, const std::string& text);
protected:
void Load_Font();
virtual void Load_Text();
std::string text, font_fn;
int font_size;
SDL_Colour colour;
QUALITY quality;
Uint8 alpha;
TTF_Font* font;
raw_surface_ptr surface;
private:
// Functions Text shouldn't expose.
virtual const PointI Get_Size() const { return Get_Surface_Size(); }
virtual void Set_Size(const PointI& size) {}
virtual void Update(const SDL_Event* event_) {}
virtual bool Blocks_Mouse(const PointI& mouse, ushort source_depth) const { return false; }
virtual bool Has_Focus() const { return false; }
};
That shows which functions Text shouldn't have and hopefully my motives.
-
Re: Polymorphism violating private access modifier
Quote:
Originally Posted by
Mybowlcut
Doesn't this violate the private access modifier somehow?
No because you're accessing the object as a Base object.
I often do this in polymorphic designs to enforce that derived type objects are used only as base type objects. Methods just aren't accessible in derived objects.
-
Re: Polymorphism violating private access modifier
Quote:
Originally Posted by
nuzzle
No because you're accessing the object as a Base object.
I often do this in polymorphic designs to enforce that derived type objects are used only as base type objects. Methods just aren't accessible in derived objects.
How can they not be accessible considering my first post's sample code and output?
-
Re: Polymorphism violating private access modifier
Quote:
Originally Posted by
Mybowlcut
How can they not be accessible considering my first post's sample code and output?
B* b = new B;
Base* base = b; // upcast okay because a B type object is also a Base type object
b->Is_Mouse_Over(); // compiler error because method is private in B
base->Is_Mouse_Over(); // compiles okay because method is public in Base
So access is determined by the type of the variable at compiletime.
What method get's called is determined by the actual object type at runtime.
-
Re: Polymorphism violating private access modifier
Quote:
Originally Posted by
nuzzle
B* b = new B;
Base* base = b; // upcast okay because a B type object is also a Base type object
b->Is_Mouse_Over(); // compiler error because method is private in B
base->Is_Mouse_Over(); // compiles okay because method is public in Base
So access is determined by the type of the variable at compiletime.
What method get's called is determined by the actual object type at runtime.
Sorry, I understand that, but I still don't understand how you would enforce that a virtual function declared as private in a derived class but declared public in the base class is not called from a base class object such as the one in my example.
This has brought up another problem for me... that is, I have a shared_ptr<GUI_Object> and want to have a property grid that displays the properties of the object - how would I get an instance of that type of object if all I have to go by is a string containing the type of the object? Can someone please suggest a better design? This one is horrible. :sick:
-
Re: Polymorphism violating private access modifier
Quote:
Originally Posted by
Mybowlcut
Sorry, I understand that, but I still don't understand how you would enforce that a virtual function declared as private in a derived class but declared public in the base class is not called from a base class object such as the one in my example.
You cannot enforce something that is in contrast to the mechanism you use. Public inheritance means is-a, so if you say that Text is a GUI_Object, then Text must behave like a GUI_Object. What you want to express is that Text is sort of a bit like a GUI_Object, which is not what public inheritance expresses.
Besides, what would you expect to happen. The compiler does not (necessarily) know what's the derived object that you are calling the function on, so it cannot give you an error. Are you expecting a private_function_exception to be thrown?
-
Re: Polymorphism violating private access modifier
Quote:
Sorry, I understand that, but I still don't understand how you would enforce that a virtual function declared as private in a derived class but declared public in the base class is not called from a base class object such as the one in my example.
Don't think it's possible without redesigning the language. As nuzzle said the concept of "private" only exists at compile-time. You're asking the virtual call mechanism to enforce access restrictions at runtime, which it's totally incapable of doing in its current form.
I don't have the standard in front of me at the moment, but I wouldn't be surprised if what you're doing is undefined behavior. The whole point of polymorphism is to be able to access a certain functionality through an interface defined by the base class, so if a derived class decides to change that interface.... all bets are probably off.
-
Re: Polymorphism violating private access modifier
Quote:
Originally Posted by Speedo
I don't have the standard in front of me at the moment, but I wouldn't be surprised if what you're doing is undefined behavior.
It is well defined, and C++03 section 11.6 even has a direct example of what happens when the derived class overrides a public virtual member function to have private access.
nuzzle cited what sounds like a plausible use of this feature, but frankly its use feels like abuse. (That rhymes!)
-
Re: Polymorphism violating private access modifier
Quote:
Originally Posted by
laserlight
nuzzle cited what sounds like a plausible use of this feature, but frankly its use feels like abuse. (That rhymes!)
maybe, nuzzle's pattern is a "low cost" alternative to the use of private virtuals and public forwarders whenever the latter are not allowed. That sead, the idea of a class that does not fully include its public base public interface is quite counterintuitive ( argh, no rhymes! :D )
-
Re: Polymorphism violating private access modifier
Quote:
Originally Posted by superbonzo
nuzzle's pattern is a "low cost" alternative to the use of private virtuals and public forwarders whenever the latter are not allowed.
As in the non-virtual interface idiom? It seems a little different though, since with NVI you can use the function given just an object of the derived class, but with respect to nuzzle's use you really need a base class pointer/reference/object.
-
Re: Polymorphism violating private access modifier
Quote:
Originally Posted by
laserlight
As in the non-virtual interface idiom? .
yes ...
Quote:
Originally Posted by
laserlight
It seems a little different though, since with NVI you can use the function given just an object of the derived class, but with respect to nuzzle's use you really need a base class pointer/reference/object.
... and yes .
I didn't mean they are equivalent and I'm not fostering it. But in this way you have a bit more control on the way polymorhic behaviour is invoked compared to only public virtuals. For example, you can always convert it to NVI by modifyng only the code accessing base objects without touching code explicitly using derived classes public interfaces.
-
Re: Polymorphism violating private access modifier
Quote:
Originally Posted by
superbonzo
maybe, nuzzle's pattern is a "low cost" alternative to the use of private virtuals and public forwarders whenever the latter are not allowed. That sead, the idea of a class that does not fully include its public base public interface is quite counterintuitive ( argh, no rhymes! :D )
I've never thought about it really because I find it so natural,
Code:
class Base {
public:
// pure virtual interface (the Base type)
};
//
class Derived : public Base {
private:
// implementation of the Base type
};
In a polymorphic design most of the time the above is exactly what you want.
When a Derived class is instantiated it's immediately assigned to a Base variable. It's not used in any other way so there's no need for it to publicly expose the interface it has implemented. This is the ultimate encapsulation really.
If anyone sees a problem with this I would be very interested to hear about it because I'm using this approach quite alot.
-
Re: Polymorphism violating private access modifier
Quote:
Sorry, I understand that, but I still don't understand how you would enforce that a virtual function declared as private in a derived class but declared public in the base class is not called from a base class object such as the one in my example.
If you don't want the function to be called by the base class then:
1. don't declare it as abstract in the base class and
2. don't provide an implementation of it in your derived class.
Your current design would be useful if you want typical polymorphic behaviour on your derived class, but want to make sure that the function can't be called outside of the inheritance hierarchy.
Cheers,
BJW
-
Re: Polymorphism violating private access modifier
Quote:
Originally Posted by
nuzzle
In a polymorphic design most of the time the above is exactly what you want.
When a Derived class is instantiated it's immediately assigned to a Base variable. It's not used in any other way so there's no need for it to publicly expose the interface it has implemented. This is the ultimate encapsulation really.
That's a different story, you are privately inheriting from Base. Among other things this means that you must supply some factory (static member or friend non member) function in order to "assign" it to a Base variable. Certainly this is a stronger form of encapsulation but I don't known how many here would define that sort of design the prototypical polymorphic design.
-
Re: Polymorphism violating private access modifier
Quote:
Originally Posted by
superbonzo
That's a different story, you are privately inheriting from Base.
That's a mistake, it should be public inheritance. I correct it in my previous post.
-
Re: Polymorphism violating private access modifier
Quote:
Originally Posted by
nuzzle
That's a mistake, it should be public inheritance. I correct it in my previous post.
ok.
Quote:
Originally Posted by nuzzle
If anyone sees a problem with this I would be very interested to hear about it because I'm using this approach quite alot.
IMHO it depends on what you consider part of the interface of the system your developing: if the interface is identifiable with your abstract base classes then that's fine; but if by interface you mean the whole semantic "world" represented by your type system ( thus including all types and functions operating on them in a specified namespace ) then you'll get in trouble if public inheritance does not imply full inclusivity of public members.
For example, suppose you have a class world::A and a function world::do_something_to(A&). Then, you can define a world::B: public A. That's fine because do_something_to(B_instance) should work properly (and this works with your use pattern). But you can also define a world::do_something_to(B&) and here come troubles because the do_something_to(B&) implementor expects that whatever you can do to an A can be done to a B.
-
Re: Polymorphism violating private access modifier
Quote:
Originally Posted by
treuss
You cannot enforce something that is in contrast to the mechanism you use. Public inheritance means is-a, so if you say that Text is a GUI_Object, then Text must behave like a GUI_Object. What you want to express is that Text is sort of a bit like a GUI_Object, which is not what public inheritance expresses.
Besides, what would you expect to happen. The compiler does not (necessarily) know what's the derived object that you are calling the function on, so it cannot give you an error. Are you expecting a private_function_exception to be thrown?
Actually, you have misunderstood what I meant. I was asking nuzzle how he would do this:
Quote:
Originally Posted by nuzzle
I often do this in polymorphic designs to enforce that derived type objects are used only as base type objects. Methods just aren't accessible in derived objects.
I misread what he wrote, as I thought he said he was somehow enforcing that derived class virtual functions weren't being called through base objects.
As for my problem, can anyone help suggesting a better design?
Quote:
Originally Posted by
Mybowlcut
This has brought up another problem for me... that is, I have a shared_ptr<GUI_Object> and want to have a property grid that displays the properties of the object - how would I get an instance of that type of object if all I have to go by is a string containing the type of the object? Can someone please suggest a better design? This one is horrible. :sick: