Blog coding and discussion of coding about JavaScript, PHP, CGI, general web building etc.

Thursday, December 29, 2016

C++ is it possible to NOT inherit a member?

C++ is it possible to NOT inherit a member?


I am pretty sure it isn't but I am going to ask anyway...
Here's an example: let's say I have a class called Elipse:

class Elipse  {  private:    double d_m_lAxis; // the length of the large Axis of the elipse    double d_m_sAxis; // short axis  //Point is a struct of 2 doubles (x and y)    Point P_m_focal1; //focal point 1    Point P_m_focal2; //focal point 2  protected:    Point P_m_center;     public:    Elipse(Point _P_lowerLeft,Point _L_upperRight)    {      //draw elipse in a rectangle, just like in paint    }  }  

Now I want to inherit Circle from Elipse (because Circle is an Elipse with both Axis of the same length):

class Circle : public Elipse     {  private:    double d_m_radius;  public:    Circle(Point _P_lowerLeft,double _d_diameter) :      Elipse(_P_lowerLeft,/*get the upper ight*/        Point(_P_lowerLeft.x + _d_diameter,_P_lowerLeft.y + _d_diameter))        {          // draw a circle in a square, just like in paint        }  }  

So now I got the class I wanted and it doesn't have the access to any of the private members of the Elipse which would become redundant in Circle.
However, as far as I know these members are still inherited and the child class simply does not have access to them. This makes the class unnecessarily large in size and it is also possible to access those members via functions inherited from Elipse, unless they are overriden.

Is there a way to not inherit a member at all?

Answer by Maciej Baranowski for C++ is it possible to NOT inherit a member?


What you're trying to achive with this inheritance violates Liskov Substitution principle. In fact in your case Ellipse should not be a base for Circle. See more details e.g. on wikipedia:

https://en.wikipedia.org/wiki/Liskov_substitution_principle#A_typical_violation - here it is explained based on very similar example (rectangle and square)

Answer by Webert S. Lima for C++ is it possible to NOT inherit a member?


A circle is a particular case of elipse, not a subtype of it, so you wouldn't need to do this. Instead, just initialize your elipse with same value for any axis.

About the inheritance, private, protected members are there for this purpose. They like private that will be inherited. The class won't be large because of the base class private members. The compiler will optimize the final code.

Answer by WhiZTiM for C++ is it possible to NOT inherit a member?


This makes the class unnecessarily large in size and it is also possible to access those members via functions inherited from Elipse, unless they are overriden. Is there a way to NOT inherit a member at all?

Though, you may want to rethink your design, You could take advantage of EBO (empty base class optimization), there will be no size overhead.

Have an empty type like:

class EllipticalType {};  

Then define your Ellipse like

class Elipse : public EllipticalType  {  private:    double d_m_lAxis; // the length of the large Axis of the elipse    double d_m_sAxis; // short axis  //Point is a struct of 2 doubles (x and y)    Point P_m_focal1; //focal point 1    Point P_m_focal2; //focal point 2  protected:    Point P_m_center;     public:    Elipse(Point _P_lowerLeft,Point _L_upperRight)    {      //draw elipse in a rectangle, just like in paint    }  }  

Then you do:

class Circle : public EllipticalType  {            private:              double d_m_radius;            public:      Circle(Point _P_lowerLeft,double _d_diameter) : Elipse(_P_lowerLeft,/*get the upper right*/Point(_P_lowerLeft.x + _d_diameter,_P_lowerLeft.y + _d_diameter))          {          // draw a circle in a square, just like in paint          }    }  

You can also extract common members and put them into EllipticalType

Answer by Yakk for C++ is it possible to NOT inherit a member?


No. You cannot. Inheritance in C++ implies a certain level of binary compatibility in practice.

A workaround follows. But first:

A circle is not an ellipse.

To be more precise, a mutable circle is not a mutable ellipse in many useful ways. There are operations you can perform on a mutable ellipse whose postconditions do not align with the same operations on a mutable circle.

For example, suppose there is get/set major/minor axis. A reasonable postcondition on set major axis is that get minor axis remains unchanges on a mutable ellipse. While you can have set major/minor axis on a circle, that postcondition cannot hold!

Now, an immutable circle is an immutable ellipse. It is only once you start editing it does the covariant/contravariant problem occur. This problem is not limited to rectangle/square, ellipse/circle, automobile/truck style "toy" OO; an editable list of Derived is not an editable list of Base either in the same way. An editable list of Base accepts any Base type; the same is not true of a list of Derived.

On the other hand, an immitable list of Derived is an immutable list of Base.


Going back to your original question, inheriting the implementations like that may be unwise. However, you could split data from logic from interface.

Then inherit interface and logic while leaving data unassociated.

In C++ this can be done with templates and CRTP. If you do not know CRTP the following will be arcane and unreadable. I do not guarantee the countrapositive.

template  struct ellipse_math {    Self* self(){ return static_cast(this);}    Self const* self() const { return static_cast(this);}      double get_area() const { /* math using self()->get_major() and self()->get_minor(); */ }  };  struct circle_state {    double m_radius;    double get_major() const;    double get_minor() const;    double get_radius() const;  };  struct ellipse_state {    double m_major, m_minor;    double get_major() const;    double get_minor() const;  };  struct I_ellipse {    virtual double major()const=0;    virtual double minor()const=0;    cirtual double area()const=0;    virtual ~I_ellipse(){};  };  struct I_circle:I_ellipse {    virtual double radius()const=0;  };  template  struct impl_I_ellipse : I  {    Self* self(){ return static_cast(this);}    Self const* self() const { return static_cast(this);}    virtual double major()const final override { return self()->get_major(); }    virtual double minor()const final override { return self()->get_minor(); }    virtual double area()const final override { return self()->get_area(); }  };  template  struct impl_I_circle : impl_I_ellipse {    Self* self(){ return static_cast(this);}    Self const* self() const { return static_cast(this);}    virtual double radius()const final override { return self()->get_radius(); }  };    struct ellipse :    ellipse_state,    impl_I_ellpise,    ellpise_math  {};  struct circle  :    circle_state,    impl_I_circle,    ellpise_math  {};  

This is pretty ridiculous in this simple case, but I did avoid having unused ellipse fields in my circle implementation, and got to reuse the ellpise logic.

The above was typed on a phone, so probably contains tpyos.

Honestly if I was going this far, I'd go all the way to SBO type erasure of ellipse-like and circle-like objects using free functions for dispatch. Because the inheritance above and vtable are getting in the way more than they are helpimg.

Answer by StoryTeller for C++ is it possible to NOT inherit a member?


The mathematical phrasing "a circle is an ellipse where [...]" should be rephrased to the more type aware "For every circle, there exists an ellipse where [...], that describes the same set of points".

With that in mind, your implementation should allow the creation of Ellipse objects from Circle objects, but not polymorphic substitution.
One such possibility, is an explicit conversion operator:

class Elipse  {    // as you defined  };    class Circle  {    // As you defined    explicit operator Ellipse()    {      Point lower_left, upper_right;      // calculate the two points      return Ellipse(lower_left, upper_right);    }  };  


Fatal error: Call to a member function getElementsByTagName() on a non-object in D:\XAMPP INSTALLASTION\xampp\htdocs\endunpratama9i\www-stackoverflow-info-proses.php on line 72

0 comments:

Post a Comment

Popular Posts

Powered by Blogger.