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.
Related
I'm trying to implement a menu for my Shape program. I've implemented all of the shapes classes. Two are deriving straight from the abstract class "Shape", and two others are deriving from a class called "Polygon" which derives from "Shape" as shown bellow:
Shape -> Polygon -> Rectangle, Triangle
`-> Circle, Arrow
In my menu class, I want to create some sort of an array that can contain the pointers to the objects and with the type of the base class "Shape". But I'm not sure how to do it properly and in a way which will work for all of my shapes, because 2 of my classes aren't deriving from "Shape" directly.
This is my menu class:
class Menu
{
protected:
//array of derived objects
public:
Menu();
~Menu();
// more functions..
void addShape(Shape& shape);
void deleteAllShapes();
void deleteShape(Shape& shape);
void printDetails(Shape& shape);
private:
Canvas _canvas; //Ignore, I use this program to eventually draw this objects to a cool GUI
};
And in the function "addShape(Shape& shape);", Which I want to use to add each given shape to my array. How can I implement the addition of new objects to it? And also, how can I check if the given object is deriving from "Polygon" or not? Because if so then I need to call the member functions differently as far as I understand.
I see that you have an array in Menu, let's say:
Shape* myshapes[10];
The shapes can be Rectangles, Triangles, Circles etc.
What you want is to be able to use the Menu's printDetails() method like this:
void printDetails()
{
for(int i = 0; i < size; i++)
{
cout << "Index " << i << " has " << myshapes[i]->getShapeName() << endl;
}
}
The getShapeName() will return a string, e.g. "Rectangle" if it is Rectangle.
You will be able to do this with the help of pure virtual function. The pure virtual function must be in the abstract class Shape, which has:
virtual string getShapeName() = 0; //pure virtual
It means that we are expecting a definition for this function in the derived class. This way you will be able to use getShapeName() method using the Shape pointers in the shapes array, which will tell you whether the shape is Rectangle, Triangle, or Circle etc.
class Shape
{
public:
virtual string getShapeName() = 0;
};
class Circle : public Shape
{
private:
int radius;
public:
Circle(int r) { radius = r; cout << "Circle created!\n"; }
string getShapeName() { return "Circle"; }
};
class Arrow : public Shape
{
private:
int length;
public:
Arrow(int l) { length = l; cout << "Arrow created!\n"; }
string getShapeName() { return "Arrow"; }
};
class Polygon : public Shape
{
public:
virtual string getShapeName() = 0;
};
class Triangle : public Polygon
{
private:
int x, y, z;
public:
Triangle(int a, int b, int c) { x = a; y = b; z = c; cout << "Triangle created!\n"; }
string getShapeName() { return "Triangle"; }
};
class Rectangle : public Polygon
{
private:
int length;
int width;
public:
Rectangle(int l, int w){ length = l; width = w; cout << "Rectangle created!\n"; }
string getShapeName() { return "Rectangle"; }
};
To implement the addShape() method you can do this:
void addShape(Shape &shape)
{
myshapes[count] = &shape;
count++;
}
Also, keep in mind to pass the Shape by reference or by using pointer, in the addShape() method.
I hope this helps... Best of luck :-)
The function "foo" is from external library (In my case DEAlII ).
It takes in class type as template parameter and its object. It then creates a copy of this object and performs some operation on this object.
The problem is when the input class is polymorphic (template ). Then I always pass base class object but pointing to different derived class, but the copied object in the function "foo" will be base class.
And any call to member function on this copied object will call base class member function(But I need them to call to corresponding derived class member function).
Additionally the type of derived class is decided at runtime based on some input parameter. I cannot change/ move to different library, but I should be able to modify the function "foo" in the library(preferably not but may be as a last resort).
#include <iostream>
#include <memory>
using namespace std;
class Shape {
protected:
int width, height;
public:
Shape( int a = 0, int b = 0){
width = a;
height = b;
}
void set(int a){
width =a ;
}
virtual int area() {
cout << "Parent class area :" <<endl;
return 0;
}
virtual ~Shape()=default;
};
class Rectangle: public Shape {
public:
Rectangle( int a = 0, int b = 0):Shape(a, b) { }
int area () override{
cout << "Rectangle class area :" <<width*height <<endl;
return (width * height);
}
};
class Triangle: public Shape {
public:
Triangle( int a = 0, int b = 0):Shape(a, b) { }
int area () {
cout << "Triangle class area :" <<endl;
return (width * height / 2);
}
Triangle(const Triangle &triangle){
width = triangle.width;
height = triangle.height;
}
};
template <class temp>
void foo (temp &shape){
shape.area();
temp shape_sample = shape;
shape_sample.area();
}
// Main function for the program
int main() {
unique_ptr<Shape> shape;
Rectangle rec(10,7);
shape =make_unique<Rectangle> (rec);
foo (*shape.get());
shape->area();
return 0;
}
If the implementation of foo can't be change then I see two options here:
Option 1: Simply downcast to appropriate type if you know what it is:
foo(static_cast<Rectangle &>(*shape.get()));
Option 2 (overkill): hide the polymorphism using Bridge pattern:
class Shape {
protected:
class ShapeImpl {
public:
int width, height;
virtual ~ShapeImpl() = default;
// "virtual copy constructor" which you could've used without a Bridge
// if you could change "foo"
virtual ShapeImpl *clone() { return new ShapeImpl(*this); }
virtual int area() {
cout << "Parent class area :" <<endl;
return 0;
}
} *impl; // can't use unique_ptr because we want copy
Shape(ShapeImpl *impl)
: impl(impl) { }
public:
Shape(const Shape &other)
: impl(other.impl ? other.impl->clone() : nullptr) {
}
Shape(Shape &&other)
: impl(nullptr) {
std::swap(impl, other.impl);
}
virtual ~Shape() {
delete impl;
}
// copy-and-swap idiom with one assignment operator to "rule-of-five them all"
Shape &operator=(Shape other) {
std::swap(impl, other.impl);
return *this;
}
int area() {
return impl->area();
}
};
class Rectangle : public Shape {
protected:
class RectangleImpl : public ShapeImpl {
public:
ShapeImpl *clone() override { return new RectangleImpl(*this); }
int area() override {
cout << "Rectangle class area :" <<width*height <<endl;
return (width * height);
}
};
public:
Rectangle(int width = 0, int height = 0)
: Shape(new RectangleImpl())
{
impl->width = width;
impl->height = height;
}
};
If the implementation of the foo could not be changed. one other option is to write a wrapper around it and using dynamic cast send the right type to it.
template <class temp>
void foo (temp &shape)
{
shape.area();
temp shape_sample = shape;
shape_sample.area();
}
void fooWrapper(Shape* shape)
{
Rectangle* shape1 = dynamic_cast<Rectangle*>(shape);
if (shape1)
{
foo<Rectangle>(*shape1);
return;
}
Triangle* shape2 = dynamic_cast<Triangle*>(shape);
if(shape2)
{
foo<Triangle>(*shape2);
return;
}
shape->area();
return;
}
// Main function for the program
int main() {
unique_ptr<Shape> shape;
Triangle tri(10,7);
shape =make_unique<Triangle> (tri);
fooWrapper(shape.get());
Rectangle rec(10,7);
shape = make_unique<Rectangle> (rec);
fooWrapper(shape.get());
return 0;
}`
How to resolve not a member of base class when create derived object using new operator
When i execute the below program, i am getting the below error only when i create a object using new operator "shape *s=new Rectangle";. But i havent faced any issues when i create object "Rectangle s"
Actually i dont want to use hello method in my Triangle class. Need to acces/uses hello method in rectangle class by creating object using new operator "shape *s=new Rectangle".
Please let us know how to resolve this issue using new operator.
Error:
1>c:\shape\shape\shape.cpp(60) : error C2039: 'hello' : is not a member of 'Shape'
1>c:\shape\shape\shape.cpp(10) : see declaration of 'Shape'
Code snippet:
// Shape.cpp : Defines the entry point for the console application.
//
#include <iostream>
using namespace std;
// Base class
class Shape
{
public:
// pure virtual function providing interface framework.
virtual int getArea() = 0;
void setWidth(int w)
{
width = w;
}
void setHeight(int h)
{
height = h;
}
protected:
int width;
int height;
};
// Derived classes
class Rectangle: public Shape
{
public:
int getArea()
{
return (width * height);
}
void hello()
{
std:cout<<std::endl<<"hello"<<std::endl;
}
};
class Triangle: public Shape
{
public:
int getArea()
{
return (width * height)/2;
}
};
int main(void)
{
Shape *s= new Rectangle;
// Triangle Tri;
s->setWidth(5);
s->setHeight(7);
// Print the area of the object.
cout << "Total Rectangle area: " << s->getArea() << endl;
s->hello();
/*
Tri.setWidth(5);
Tri.setHeight(7);
// Print the area of the object.
cout << "Total Triangle area: " << Tri.getArea() << endl;
*/
return 0;
}
You have a pointer to Shape, but (and this is what your compiler tells you) Shape has no member hello().
So theres two ways to access it:
Either you cast it to Rectangle* first (which might fail for non-rectangles) or you create a function virtual void hello() in Shape which is then resolved at compile-time - for all classes that inherit from Shape.
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';
}
class Polygon {
protected:
int width, height;
public:
void set_values (int a, int b)
{ width=a; height=b; }
};
class Rectangle: public Polygon {
public:
int area()
{ return width*height; }
};
int main () {
Rectangle rect;
Polygon * ppoly1 = ▭
ppoly1->set_values (4,5);
cout << rect.area() << '\n';
return 0;
}
In above example, what does ppoly1 points to and how is this pointer not able to access rectangle class's function?
WHY ppoly1->area() is an error
Thanks!
The expression ppoly1->area() is an error because ppoly1 is typed to Polygon which has no area method declared. When C++ tries to evaluate this member it essentially starts at Polygon sees no member named area and hence issues an error
It sounds like you want to give the Polygon type the notion of an area method without an implementation (forcing the derived types to provide one). If that is the case then you should declare an un-implemented virtual method in Polygon
class Polygon {
...
virtual ~Polygon() { }
virtual int area() = 0;
};
Base classes know nothing about their derived classes. When a base class is being defined there is no yet any derived class.
Variable ppoly1 is of the type Polygon *. Class Polygon has no method area so the compiler issues the error.
If you want to use a common interface for derived classes you should declare it in the base class. For example
class Polygon {
protected:
int width, height;
public:
void set_values (int a, int b)
{ width=a; height=b; }
virtual int area() const = 0;
virtual ~Polygon(){}
};
class Rectangle: public Polygon {
public:
int area() const
{ return width*height; }
};
int main () {
Rectangle rect;
Polygon * ppoly1 = ▭
ppoly1->set_values (4,5);
cout << rect.area() << '\n';
return 0;
}
ppoly1 is a Polygon pointer. The fact that the pointer points to a Rectangle object does not enable it to call Rectangle functions; the type is still Polygon*. To enable it to call Rectangle functions you need to either make it a Rectangle pointer, or implement a virtual method in your Polygon class,
e.g.
virtual int area() const;
This means that when a Polygon object has area() called on it, it will go looking for the most derived instance of area(). On ppoly1 this will be Rectangle->area(). You can keep your Rectangle code the same as before.
Wikipedia on virtual functions: http://en.wikipedia.org/wiki/Virtual_function