I have a virtual inheritance example like below:
class Polygon {
public:
virtual double area() = 0;
};
class Rectangle : public virtual Polygon {
double a, b;
public:
Rectangle(double a, double b) {
this->a = a;
this->b = b;
}
double area() { return a * b; }
};
class Rombus : public virtual Polygon {
double a, h;
public:
Rombus(double a, double h) {
this->a = a;
this->h = h;
}
double area() { return a * h; }
};
class Square : public Rectangle, public Rombus {
public:
Square(double a) : Rectangle(a, a), Rombus(a, a) {}
};
It is one of requirements that Suare has to inherit from Rectangle and Rombus. That's why I use virtual inheritance.
But then I got an error:
override of virtual function "Polygon::area" is ambiguous
'Square': ambiguous inheritance of 'double Polygon::area(void)'
What am I doing wrong?
The error message is:
'Square': ambiguous inheritance of 'double Polygon::area(void)'
It should be obvious why: there are two implementations!
double area() { return a * b; } // in Rectangle
double area() { return a * h; } // in Rhombus
Square inherits both of them, so there is no possible way the compiler could know which to use.
You can "fix" it by overriding area() in Square as well.
This design is deficient from the start: a Square should only contain a single member, its width/height. But yours contains four members, all of which will always have the same value!
Related
I am getting a compiler error saying that the data member Point p is private within the context, when I declare Point p as private within class circle. The code and compiler error are below.
#include<iostream>
#include<vector>
class Point
{
public:
Point(double a, double b)
{
x = a;
y = b;
}
virtual ~Point(){}
private:
double x;
double y;
};
The code for the class shape and circle are as follows:
class shapes {
public:
virtual Point centre() const = 0;
virtual void draw() const = 0;
virtual void rotate(int angle) const = 0;
virtual ~shapes(){}
};
class circle: public shapes {
public:
Point centre() const override { return p; }
void draw() const override { }
void rotate(int angle) const override {}
virtual ~circle() {}
circle(Point x, int r):p{x},radius{r}{}
private:
Point p;
int radius; };
Edit: Smiley face class inherits from circle class with code below:
class smiley: public circle
{ //smiley face is a circle + eyes and mouth
public:
smiley(Point p, int r):circle{p,r},mouth{nullptr}{}
Point centre() const override { return p;}
void draw() const override
{
//draw circle
circle::draw();
for(auto e:eyes)
{
e->draw();
}
mouth->draw();
}
void rotate(int angle) const {}
virtual ~smiley()
{
delete mouth;
for (auto eye : eyes) //why not delete [] eyes
{
delete eye;
}
}
private:
std::vector<shapes*> eyes; //smiley face has eyes
shapes* mouth; //smiley face has a mouth
};
If I make the data member p public in the class circle, everything works. The compiler error is listed below:
Why can I not define the Point object p, in the circle class private?
Edit: I have added the compiler error message and added the missing code asked for in the comments below. Would you be able to re-open the question?
Private class members can only be accessed within the class or by friends, so, if you would like it to be accessed outside the class by a non-friend, you would need to use a setter/getter.
I understand that you can access members of the base class from a derived class, however, I have a function that requires a pointer to my base class as a whole. For example:
#include <iostream>
using namespace std;
function foo(Shape &s){
//does something
}
// Base class
class Shape {
public:
Shape(int w = 100, int h = 100){
width = w;
height = h;
}
void setWidth(int w) {
width = w;
}
void setHeight(int h) {
height = h;
}
protected:
int width;
int height;
};
// Derived class
class Rectangle: public Shape {
public:
Rectangle(){
Shape();
}
int getArea() {
return (width * height);
}
};
int main(void) {
Rectangle Rect;
foo(// Pointer Reference to Rect.Shape here);
return 0;
}
Is there any way to get a pointer to this base class from the derived class?
Here's a working version of your code. I made some changes to it and added comments to explain the changes. Your program requires polymorphism to behave as expected, otherwise you'll 'slice' your derived object and just have a Base object.
#include <iostream>
#include <string>
// Base class
// Your base should only have things that would be common to all derived classes
// Consider what the width and height of a Circle would be
//
// You may not have gotten to virtual functions and polymorphism yet. This is
// how you would set up an interface for your Derived classes. I am requiring
// any derived class to implement getArea() and identify() if it wants to be a
// 'concrete' class. Otherwise it will be abstract, which means you can't
// declare objects of that type. It is not possible to declare a Shape object
// because of the pure virtual functions
class Shape {
public:
virtual ~Shape() = default; // A virtual destructor is required
virtual double getArea() const = 0; // Pure virtual function
virtual std::string identify() const = 0;
};
// Derived class
class Rectangle : public Shape {
public:
// The base class should be initialized in the constructor's
// initialization section. What you did was declare a temporary Shape that
// went away when the function ended.
// All class data should be set in the initialization section
Rectangle(int w, int h) : Shape(), width(w), height(h) {}
double getArea() const override { return (width * height); }
std::string identify() const override { return "Rectangle"; }
private:
int width = 0;
int height = 0;
};
// A new derived class that should work (a circle **is-a** shape), but doesn't
// with your setup. Circles don't have width and height
class Circle : public Shape {
public:
Circle(int r) : Shape(), radius(r) {}
double getArea() const override { return 2 * 3.14 * radius * radius; }
std::string identify() const override { return "Circle"; }
private:
int radius = 0;
};
// Subjective, I moved the function below the class definitions and added a body
void foo(Shape &s) {
std::cout << "A " << s.identify() << " with area " << s.getArea() << ".\n";
}
int main(void) {
Rectangle rect(5, 3);
foo(rect);
Circle circ(4);
foo(circ);
return 0;
}
Output:
A Rectangle with area 15
A Circle with area 100.48
If I remove all the virtual stuff, a lot of things stop working. I now have to provide implementations for the Shape functions. That logically doesn't make much sense. And while I can pass my derived objects to foo(), they get sliced, and the filler Shape data gets printed instead.
Is it possible to achieve behaviour demonstrated below with virtual functions? And if it's not the correct way to go about polymorphism then what would be the correct way in this example?
class Base_
{
float x;
float y;
float z;
public:
Base_(float xx=0, float yy=0, float zz=0)
{
x = xx;
y = yy;
z = zz;
}
virtual void SetParemeters(what here?)=0; //Different number of arguments
};
class Derived_1 :public Base_
{
float r;
public:
Derived_1(float rr=1, float xx=0, float yy=0, float zz=0):Base_(xx,yy,zz)
{
r=rr;
}
virtual void SetParemeters(float v1) //Different number of arguments
{
r=v1;
}
};
class Derived_2 :public Base_
{
float k;
float w;
public:
Derived_2(float kk=1, float ww=1,float xx=0, float yy=0, float zz=0):Base_(xx,yy,zz)
{
k=kk;
w=ww;
}
virtual void SetParemeters(float v1, float v2) //Different number of arguments
{
k=v1;
w=v2;
}
};
int main()
{
Derived_1 d1;
Derived_2 d2;
Base_ *ptr;
ptr = &d1;
ptr -> SetParemeters(one argument)
ptr = &d2;
ptr-> SetParemeters(one or two arguments)
return 0;
}
And even if I managed to achieve that, how can I set only second parameter (k) here: ptr-> SetParemeters(one or two arguments)?
I searched for answers but I only found answers to specific scenarios which made the whole thing difficult for me to understand.
Yes, make Base_::SetParameters takes two (optional) arguments:
class Base_
{
// [...]
public:
virtual void SetParemeters(float=0f, float=0f)=0;
};
Derived_1::SetParameters just ignores the first one:
class Derived_1 :public Base_
{
// [...]
virtual void SetParemeters(float v1, float=0f)
{
r=v1;
}
};
while Derived_2 takes the both of them
class Derived_2 :public Base_
{
// [...]
virtual void SetParemeters(float v1, float v2)
{
k=v1;
w=v2;
}
};
demo: https://coliru.stacked-crooked.com/a/c528ffff005df5b9
Note though, this significantly reduces the interest of virtual functions...
Derived_1 d1;
Derived_2 d2;
Base_ *ptr;
ptr = &d1;
ptr->SetParameters(one argument)
ptr = &d2;
ptr->SetParameters(one or two arguments)
The way how this code is written implies that you have knowledge about two things:
at the time of the first call to SetParameters(), ptr points to an object of type Derived_1
at the second call, it points to an object of type Derived_2.
This in turn means that you know the static types -- and in fact, you need to, due to the different signatures.
For such a scenario, dynamic polymorphism is not the right choice, because its premise is that you can talk to different implementations (overridden methods) using a uniform access (calling the virtual base method).
So, if you have this knowledge at compile time, simply use non-virtual method calls.
However, there are similar scenarios where you may actually be interested in supporting different signatures at runtime, for example if you load configuration dynamically. Here is an example, where not the number, but the types of arguments differ.
class Car : public Vehicle
{
virtual void addFuel(const Petrol& f) override;
};
class Airplane : public Vehicle
{
virtual void addFuel(const Kerosene& f) override;
};
How would then the base function look?
class Vehicle
{
virtual ~Vehicle() {} // don't forget this!
virtual void addFuel(const /* which type? */& f) = 0;
};
One option is to make the fuel type a hierarchy as well (both Kerosene and Petrol inherit the Fuel class):
class Vehicle
{
virtual ~Vehicle() {}
virtual void addFuel(const Fuel& f) = 0;
};
However, in this case, each implementation would need to either rely on the fact it's passed the right fuel, or check the type at runtime.
class Airplane : public Vehicle
{
virtual void addFuel(const Fuel& f) override
{
if (auto* k = dynamic_cast<const Kerosene*>(&f))
{
// use concrete fuel
}
}
};
You can make SetParameters a variadic function and have the polymorphic interface be internal, providing the writeable parameters in a generic form (here as a vector of pointers to them):
class Base_
{
float x;
float y;
float z;
public:
Base_(float xx=0, float yy=0, float zz=0)
{
x = xx;
y = yy;
z = zz;
}
virtual std::vector<float*> getAllExtraParameters() = 0;
template<class ... Ts>
void SetExtraParameters(Ts&& ... ts)
{
auto extras = getAllExtraParameters();
if (sizeof...(ts) > extras.size())
throw std::runtime_error("Too many parameters given!");
// Fold expression - could be implemented differently in C++ < 17.
int index = 0;
((*extras[index++] = ts), ...);
}
};
class Derived_1 :public Base_
{
float r;
public:
Derived_1(float rr=1, float xx=0, float yy=0, float zz=0):Base_(xx,yy,zz)
{
r=rr;
}
std::vector<float*> getAllExtraParameters() override
{
return { &r };
}
};
class Derived_2 :public Base_
{
public:
float k;
float w;
Derived_2(float kk=1, float ww=1,float xx=0, float yy=0, float zz=0):Base_(xx,yy,zz)
{
k=kk;
w=ww;
}
std::vector<float*> getAllExtraParameters() override
{
return { &k, &w };
}
};
Demo and tests: https://godbolt.org/z/ofXnuH
In C++, I have two separate base classes, each of whose derived classes are somewhat coupled. Here's an example for the kind of thing I'd like to do:
First define a set of classes, e.g.,:
class Shape
{
public:
double area;
double diameter;
};
class Rectangle : public Shape
{
public:
double width;
double height;
};
class Circle : public Shape
{
public:
double radius;
};
The second set of classes then pertains to operations being performed on this first set of classes, something like this:
class Calculator
{
public:
static Calculator *create_calculator(shape *shape,const char *shape_type); // the factory
virtual void calculate()=0; // the actual calculation
};
class area_circles : public Calculator
{
class circles *circle;
public
area_circles(circles *circle)
{
this->circle = circle;
}
void calculate()
{
this->area = PI*pow(circle->radius,2);
}
}
class area_rectangles : public Calculator
{
class rectangles *rectangle;
public
area_rectangles(rectangles *rectangle)
{
this->rectangle = rectangle;
}
double calculate()
{
this->area = rectangle->height * rectangle->width;
}
}
Calculator *Calculator::create_calculator(shape *shape, const char *shape_type)
{
if (shape_type=="circle")
return new area_circles(shape);
if (shape_type=="rectangle")
return new area_rectangles(shape);
}
Then, the idea would be to call all this using something like:
rectangles *my_rectangle;
Calculator *area_calculator;
area_calculator = area_calculator->create_calculator(my_rectangle, "rectangle");
area_calculator->calculate();
However, this doesn't compile and I get an error (quite sensibly) pointing out how the Shape class has no member "width", and that "a value of type "shape *" cannot be assigned an entity of type "rectangles". The error's pretty clear on why this code isn't working.
Would anyone know how to get the code here to do what I'm trying to do?
From a design perspective, I recognize that part of the problem is that the derived classes end up being coupled, so maybe there is a better way to try to decouple the calculator class from the shape class. But I'd like to at least try out this approach for a while as well in my implementation, and for that I need the code to compile.
I am not entirely sure what you are trying to achieve here but I think the more usual approach to it is something like this:
class Shape
{
public:
virtual ~Shape() {}
// concrete classes must implement this function
virtual double get_area() const = 0;
};
class Circle
: public Shape
{
double diameter;
public:
Circle(double diameter): diameter(diameter) {}
virtual double get_area() const
{
return M_PI * diameter * diameter / 4;
}
};
class Rectangle
: public Shape
{
double width;
double height;
public:
Rectangle(double width, double height): width(width), height(height) {}
virtual double get_area() const
{
return width * height;
}
};
int main()
{
Circle c(2);
Rectangle r(20, 40);
// use Shape references (or pointers) to invoke polymorphic behaviour
Shape& cs = c;
Shape& rs = r;
std::cout << "Area of circle : " << cs.get_area() << '\n';
std::cout << "Area of rectangle: " << rs.get_area() << '\n';
}
I'm trying to inherit from one of my class 2 variables which they must be equal to be able to return the value of one of my functions in the other class..
class Rectangle: public Shape{
double Length;
double Width;
public:
Rectangle(double Length, double Width):
Shape("Rectangle")
{
this->Length=Length;
this->Width=Width;
}
double getPerimerter(){
return 2 * (Length+Width);
}
double getArea(){
return Length * Width;
}
};
class Square: public Shape, public Rectangle{
double Side;
public:
Square():
Shape("Square"),
Rectangle(Length,Width)
{}
double getPerimerter(){
if(Length==Width)
return 4 * (Length+Width);
}
double getArea(){
if(Length==Width)
return (Length+Width) * (Length+Width);
}
};
as you can see I have already a concrete class call Rectangle which hold to private variables with the names Length and Width.. What I'm trying to do is inherit this class to my class Square and if Length and Width are equal then I can return the Area and Perimeter of the Square..
It is perfectly fine to inherit from an existing class.
What you probably want, however, is this:
class Square: public Rectangle
{
public:
Square(double Side) : Rectangle(Side, Side) { }
};
That way, there is no problem of someone trying to use a ractangular square Square(4.3, 9.6).
Alternatively, you could of course use typedef Rectangle Square;
Edit:
To overcome the "name", we could do something like this:
class Rectangle
{
public:
Rectangle(double Length, double Width) : Shape("Rectangle") { ... }
protected:
Rectangle(double Length, double Width, const char *name) : Shape(name), Length(Length), Width(Width) {}
};
class Square
{
public:
Square(double side) : Rectangle(side, side, "Square") {}
};
Edit2: Code that I came up with:
#include <iostream>
using namespace std;
class Shape
{
private:
const char *name;
public:
Shape(const char *name) : name(name) {}
virtual double getPerimeter() = 0;
virtual double getArea() = 0;
};
class Rectangle: public Shape{
double Length;
double Width;
public:
Rectangle(double Length, double Width):
Shape("Rectangle")
{
this->Length=Length;
this->Width=Width;
}
double getPerimeter(){
return 2 * (Length+Width);
}
double getArea(){
return Length * Width;
}
protected:
Rectangle(double Length, double Width, const char *name):
Shape(name)
{
this->Length=Length;
this->Width=Width;
}
};
class Square: public Rectangle
{
public:
Square(double Side):
Rectangle(Side,Side, "Square")
{
}
};
int main()
{
Square sq(10.0);
Rectangle rect(12.0, 4.0);
cout << "sq:" << sq.getArea() << " rect:" << rect.getArea() << endl;
}
As a first thing you should add an argument to Square constructor, like so:
Square(double Side):Rectangle(Side,Side){
// Add additional constructor code here if required
}
About returning a value in a constructor - that is a no-go as the constructor might not return anything.
I hope this is what you meant as your question was quite hard for me to understand.
I might not understand your question, but it looks to me like you only need to add a parameter to your Square() constructor. It would look like this:
class Square: public Rectangle{
public:
Square(double dimension):
Rectangle(dimension, dimension){
}
};
There is no need for a conditional statement in the Square() constructor. Creating a Square necessarily implies creating a Rectangle with equal length and width.