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;
}`
Related
So I saw this thread: What does it mean to "program to an interface"?. Which talks about declaring a Parent, but initializing it as a Child. Is it possible to do the same but with c++? For example: I have an interface Shape which can be implemented as Triangle or Square.
I tried to do the following but my program didn't compile:
Shape * myShape = new Square();
myShape->uniquetoSquare();
"typeinfo for Shape", referenced from:
typeinfo for Triangle in Triangle.o
class Shape {
public:
Shape(){};
int height;
int width;
string color;
void sayHello(){
cout << "Hello!";
}
int getArea(){
return 0;
}
}
class Triangle: public Shape {
public:
bool obtuse;
Triangle(){
obtuse = false;
};
void sayHello(){
cout << "Hello I'm a triangle!";
}
int getArea(){
return height*width / 2;
}
}
class Square: public Shape {
public:
bool rectangular
Square(){
rectangle = true;
};
void sayHello(){
cout << "Hello I'm a square!";
}
int getArea(){
return height*width;
}
void uniqueToSquare(){
cout << "This func is only in square!";
}
}
Shape does not have a function named uniqueToSquare. Remember that if you are using a Shape, then you can only use shape-like methods.
If you want to use it as a Square, then do something like:
Square* mySquare = dynamic_cast<Square*>(myShape);
if (mySquare != nullptr) mySquare->uniqueToSquare();
This is a simple polymorphism example. Yes it is possible in C++ and is actually the heart of the benefits of Object-Oriented design
With C++ it isn't as simple as you might hope. You need virtual functions to do what you want. Modifying your example to be "good" C++.
class Shape {
public:
Shape(){}
int height;
int width;
string color;
virtual void sayHello() const {
cout << "Hello!";
}
virtual int getArea() const {
return 0;
}
//virtual destructor, no need to declare this on the derived types
virtual ~Shape() {}
}
class Triangle : public Shape {
public:
bool obtuse;
Triangle() {
obtuse = false;
}
void sayHello() const {
cout << "Hello I'm a triangle!";
}
int getArea() const {
return height*width / 2;
}
}
class Rectangle : public Shape {
public:
bool square;
Rectangle() {
square = false;
}
void sayHello() const {
cout << "Hello I'm a rectangle!";
}
int getArea() const {
return height*width;
}
void uniqueToRectangle() const {
cout << "This func is only in rectangle!";
}
}
The error your getting seems to be because of missing runtime type information RTTI. You may want to enable this but it really is unnecessary for what you want to achieve. Use dynamic cast as others have suggested (which also uses RTTI).
Shape* myShape = new Rectangle();
((Rectangle*)myShape)->uniquetoRectangle();
This is OK but remember to delete myShape; before it goes out of scope. See RAII for the use of destructors for that.
Your variable myShape is a pointer to a Shape. Your class Shape does not have a method called uniqueToSquare(). Therefore, you have an error.
The solution is to initialise myShape as a Square simply by Square myShape = Square();
Remember that it is always better to preserve the real type of an object, this is better for performance, and basically gives more information to the compiler. You only resort to dynamic polymorphism when you really have to (ie, storing polymorphic objects in an array).
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.
How can I access sideA and height members of Triangle class, and how can I access sideA of a Square class, these are both derived from Shape class?
What is the correct way to implement that?
Shapes.h:
class Shape
{
public:
virtual double getArea() = 0;
};
class Triangle : public Shape
{
public:
double sideA = 3;
double height = 2;
double getArea() {
return 0.5 * sideA * height;
}
};
class Square : public Shape
{
public:
double sideA = 4;
double getArea() {
return sideA * sideA;
}
};
Main.cpp:
int main()
{
Shape* sh = new Triangle();
std::cout << sh->getArea() << std::endl;
std::cout << sh->??? //get the height of triangle
delete sh;
}
You are trying to access information that is not available via the interface you defined, class Shape allows only the area to be accessed.
To get also the height, the proper way is to extend the interface to provide that information as well.
class Shape
{
public:
virtual double getArea() = 0;
virtual double getHeight() = 0;
};
class Triangle : public Shape
{
public:
double sideA = 3;
double height = 2;
double getArea() {
return 0.5 * sideA * height;
}
double getHeight() {
return height;
}
};
class Square : public Shape
{
public:
double sideA = 4;
double getArea() {
return sideA * sideA;
}
double getHeight() {
return sideA;
}
};
A Shape has no height. You are using the triangle polymorphically. That means you have a Shape* and can only use the interface of Shape, no matter what is the actual type of the object. If you want a Triangle then use a Triangle not a Shape. If you still want to use a Triangle and Rectangle polymorphically, then you should put the common interface into the base class. In your case, both have a sideA, so you could do:
struct Shape {
double sideA = 3;
virtual double getArea() = 0;
virtual ~Shape(){}
};
struct Triangle : public Shape {
double height = 2;
double getArea() {
return 0.5 * sideA * height;
}
};
struct Square : public Shape {
double getArea() {
return sideA * sideA;
}
};
int main() {
Shape* sh = new Triangle();
std::cout << sh->sideA;
delete sh;
}
PS: the above wasn't the whole truth. If you have a Shape* and you know that it is a Triangle* then you could use dynamic_cast, but doings such casts are often a sign for poor design. You should strive to write classes such that you do not need a cast.
Because your base class has a virtual function1, you can use the dynamic_cast conversion to check if a pointer to it is actually a pointer to one of its derived classes. This will return nullptr if it is not of the 'tested' class, or a usable pointer to the derived class, if it is:
int main()
{
Shape* sh = new Triangle();
std::cout << sh->getArea() << std::endl;
if (dynamic_cast<Square*>(sh) != nullptr) { // Check for a valid Square pointer
Square* sq = dynamic_cast<Square*>(sh);
std::cout << sq->sideA << std::endl;
}
else if (dynamic_cast<Triangle*>(sh) != nullptr) { // Check for a valid Trianlge pointer
Triangle* tr = dynamic_cast<Triangle*>(sh);
std::cout << tr->height << std::endl;
}
else {
std::cout << "Unspecified shape type: height unknown!" << std::endl;
}
delete sh;
return 0;
1 Note that, because you have a virtual function in your Shape class, you should also give it a virtual destructor:
class Shape {
public:
virtual double getArea() = 0;
virtual ~Shape() { }
};
For further discussion on the need for a virtual destructor, see here: When to use virtual destructors?.
EDIT: In your specific case, the answer given by rustyx is really the 'correct' approach; however, it is useful to understand/appreciate the use of the dynamic_cast option, as this can be the only solution if you are deriving classes from a third-party base class, which you cannot modify, and thus cannot add the equivalent of the getHeight() function to it.
You can declare the variable a Triangle* not a Shape*, this way you'll have access to the derived class and base class methods and variables:
int main()
{
Triangle* sh = new Triangle();
Square* sh2 = new Square();
std::cout << sh->getArea() << std::endl; //3
std::cout << sh2->getArea() << std::endl; //16
std::cout << sh->sideA << std::endl; //3
std::cout << sh2->sideA << std::endl; //4
delete sh;
}
To use delete sh safely you should have a virtual destructor
class Shape
{
public:
virtual double getArea() = 0;
virtual ~Shape(){} //virtual destructor
};
Since you already have an abstract class, why not use it to access the the data in the derived classes:
Here is how I would do it:
#include <iostream>
#include <memory>
class Shape
{
private:
double sideA; //shared members can be defined in base class, assuming all
//derived classes will have sideA member
protected:
Shape(double sideA) : sideA(sideA) {}//for initialization of sideA in derived classes
public:
Shape() = default;
virtual double getArea() = 0;
double getSideA() { //shared logic
return sideA;
}
virtual ~Shape(){} //virtual destructor
};
class Triangle : public Shape
{
private:
double height = 2; //specific property
public:
Triangle() : Shape(3) {} //intialize sizeA
double getHeight(){ //specific method, must instanciate Triangle to access
//for collections it's best to use interface method like getArea()
return height;
}
double getArea() override {
return 0.5 * getSideA() * height;
}
};
class Square : public Shape
{
public:
Square() : Shape(4) {} //intialize sizeA
double getArea() override {
return getSideA() * getSideA();
}
};
int main()
{
std::unique_ptr<Shape> sh(new Triangle); //smart pointer
std::unique_ptr<Shape> sh2(new Square); //smart pointer
std::cout << sh->getArea() << std::endl; //3
std::cout << sh2->getArea() << std::endl; //16
std::cout << sh->getSideA() << std::endl; //3
std::cout << sh2->getSideA() << std::endl; //4
//delete sh; //no need, smart pointer
}
Take a look at smart pointers.
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 :-)
I have created three class: Square, Rectangle and Polygon. Square is inheriting from Rectangle and Rectangle is inheriting from Polygon.
The problem is that whenever I call Square constructor, Rectangle constructor get called and I get an error. How can I solve this?
#include <iostream>
using namespace std;
// Multilevel Inheritance
class Polygon
{
protected:
int sides;
};
class Rectangle: public Polygon
{
protected:
int length, breadth;
public:
Rectangle(int l, int b)
{
length = l;
breadth = b;
sides = 2;
}
void getDimensions()
{
cout << "Length = " << length << endl;
cout << "Breadth = " << breadth << endl;
}
};
class Square: public Rectangle
{
public:
Square(int side)
{
length = side;
breadth = length;
sides = 1;
}
};
int main(void)
{
Square s(10);
s.getDimensions();
}
If I comment out the Rectangle constructor, everything works fine. But I want to have both constructors. Is there anything I can do?
You should not set members of a base class in a derived class constructor. Instead, call the base class constructor explicitly:
class Polygon
{
protected:
int sides;
public:
Polygon(int _sides): sides(_sides) {} // constructor initializer list!
};
class Rectangle: public Polygon
{
protected:
int length, breadth;
public:
Rectangle(int l, int b) :
Polygon(2), // base class constructor
length(l),
breadth(b)
{}
};
class Square: public Rectangle
{
public:
Square(int side) : Rectangle(side, side)
{
// maybe you need to do this, but this is a sign of a bad design:
sides = 1;
}
};
constructor should be
Square(int side) : Rectangle(side, side) { sides = 1; }
as Rectangle has no default constructor.