I'm currently working on my C++ assignment and I'm working through polymorphism and I keep getting error messages. Would appreciate any help. Thanks in advance!
The assignment uses a shape inheritance hierarchy that looks like this:
Circle
Two Dimensional Shape
Cylnder
Shape
Three Dimensional Shape
Below is the error messages I'm getting.
1>Circle.obj : error LNK2019: unresolved external symbol "public: __thiscall TwoDimensionalShapes::TwoDimensionalShapes(void)" (??0TwoDimensionalShapes##QAE#XZ) referenced in function "public: __thiscall Circle::Circle(void)" (??0Circle##QAE#XZ)
1>Cylinder.obj : error LNK2019: unresolved external symbol "public: __thiscall ThreeDimensionalShapes::ThreeDimensionalShapes(void)" (??0ThreeDimensionalShapes##QAE#XZ) referenced in function "public: __thiscall Cylinder::Cylinder(void)" (??0Cylinder##QAE#XZ)
I'm pretty much done with my program but I'm not sure where the problems are coming from.
Here's my source code:
#include "Cylinder.h"
#include "Circle.h"
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
// next line commented out because will now cause compile error
// Shape shpeObj; // instantiate a Shape object
cout << "The Shape object count is: " << Shape::getObjectCount() << '\n';
Circle crclObj; // instantiate a Circle object
Cylinder cyldObj; // instantiate a Cylinder object
// Count will be 2 in statement below because a Shape object is contained
// within each Circle and Cylinder object.
cout << "The Shape object count is: " << Shape::getObjectCount() << "\n";
Shape * shpePtr = &cyldObj; // declare a Shape pointer
// and have it point to the Cylinder object
Shape & shpeRef = cyldObj; // declare a Shape reference
// and have it reference the Cylinder object
// The above 2 statments are ok because a derived class object IsA base class object!
// No additional objects created, so the count is still the same.
cout << "The Shape object count is: " << Shape::getObjectCount() << "\n";
// Dynamically create 2 objects
Shape * shpePtr2 = new Circle;
Shape & shpeRef2 = *new Cylinder;
// The count should now be 4
cout << "The Shape object count is: " << Shape::getObjectCount() << "\n";
// Now destroy the 2 dynamically created objects!
delete shpePtr2;
delete &shpeRef2;
//The count should now be 2 again.
cout << "The Shape object count is: " << Shape::getObjectCount() << "\n\n";
/* Can no longer test Shape class, since it is now an Abstract Base Class (ABC)
// Test Shape class
shpeObj.setNoOfSides(0);
cout << "The number of sides is: " << shpeObj.getNoOfSides() << "\n\n";
cout << "The area of shpeObj is: " << shpeObj.Area() << '\n';
cout << "The volume of shpeObj is: " << shpeObj.Volume() << "\n\n\n";
*/
// Test Circle class
crclObj.setRadius(3.0);
cout << fixed << setprecision(4); // force use of decimal point and 4 digits of
// precision after the decimal place
cout << "The radius of crclObj is: " << crclObj.getRadius() << "\n\n";
cout << "The number of sides is: " << crclObj.getNoOfSides() << "\n\n";
cout << "The area of crclObj is: " << crclObj.Area() << '\n';
// next line no longer valid in my solution for this assignment
//cout << "The volume of crclObj is: " << crclObj.Volume() << "\n\n\n";
// Test Cylinder class
cyldObj.setRadius(5.5);
cyldObj.setHeight(2.5);
cout << "The radius of cyldObj is: " << cyldObj.getRadius() << '\n';
cout << "The height of cyldObj is: " << cyldObj.getHeight() << "\n\n";
cout << "The number of sides is: " << cyldObj.getNoOfSides() << "\n\n";
cout << "The area of cyldObj is: " << cyldObj.Area() << '\n';
cout << "The volume of cyldObj is: " << cyldObj.Volume() << "\n\n";
return 0;
}
#pragma once
class Shape
{
public:
Shape(void); //constructor
~Shape(void); //destructor
void setNoOfSides(const int &); // set the # of sides
int getNoOfSides() const; // get the # of sides
static int getObjectCount(); // get the object count
virtual double Area() const = 0; // calculate and return area
// now a pure virtual function
virtual double Volume() const; // calculate and return volume
protected:
int mNoOfSides; // represents # of sides in Shape object
static int mObjectCount; // a static member - counts the # of Shape
// objects currently instantiated
// Only one of these instantiated for the whole class!
};
#pragma once
#include "Shape.h"
class TwoDimensionalShapes :public Shape
{
public:
TwoDimensionalShapes(void); //constructor
virtual double Area() const = 0; // area of 2D shape
};
#pragma once
#include "Shape.h"
class ThreeDimensionalShapes :public Shape
{
public:
ThreeDimensionalShapes(void); // constructor
virtual double Area() const = 0; // area of 3D shape
virtual double Volume() const = 0; // volume of 3D shape
};
#pragma once
#include "TwoDimensionalShapes.h"
class Circle :public TwoDimensionalShapes
{
public:
Circle(void); // constructor
void setRadius(const double &); //set the radius
double getRadius() const; // get the radius
virtual double Area() const override; // overrides Area() method of TwoDimensionalShapes class
protected:
const static double pi; // Static member used in calculations
// Only one of these instantiated for the whole class!
double mRadius; // member used to represent radius
};
#pragma once
#include "ThreeDimensionalShapes.h"
class Cylinder :public ThreeDimensionalShapes
{
public:
Cylinder(void); // constructor
void setHeight(const double &); // set the height
double getHeight() const; // get the height
void setRadius(const double &); //set the radius
double getRadius() const; // get the radius
virtual double Area() const override; // overrides Area() method of ThreeDimensionalShapes class
virtual double Volume() const override; // overrides Volume() method of ThreeDimensionalShapes class
protected:
const static double pi; // Static member used in calculations
// Only one of these instantiated for the whole class!
double mHeight; // member used to represent height
double mRadius;
};
#include "Circle.h"
// init static data member
const double Circle::pi = 3.141592654; // init. static member
// constructor
Circle::Circle(void)
:mRadius(0.0)
{
setNoOfSides(0);
}
// used to set value for mRadius member
void Circle::setRadius(const double & setVal)
{
if (setVal > 0.0) // Make sure input is a valid value
{
this->mRadius = setVal;
}
// otherwise just leave set to original value
}
// used to return current value of mRadius member
double Circle::getRadius(void) const
{
return this->mRadius;
}
// used top calculate and return area.
double Circle::Area(void) const
{
return Circle::pi * this->mRadius * this->mRadius;
}
#include "Cylinder.h"
// init static data member
const double Cylinder::pi = 3.141592654; // init. static member
// constructor
Cylinder::Cylinder(void)
:mHeight(0.0)
{
this->setNoOfSides(3); // Why not init. this member in MIL ???
}
// used to set mHeight member
void Cylinder::setHeight(const double & setVal)
{
if (setVal > 0.0) // Make sure input is a valid value
{
this->mHeight = setVal;
}
// otherwise just leave set to original value
}
// used to return current value of mHeight member
double Cylinder::getHeight(void) const
{
return this->mHeight;
}
// used to set value for mRadius member
void Cylinder::setRadius(const double & setVal)
{
if (setVal > 0.0) // Make sure input is a valid value
{
this->mRadius = setVal;
}
// otherwise just leave set to original value
}
// used to return current value of mRadius member
double Cylinder::getRadius(void) const
{
return this->mRadius;
}
// used to caluclate and return area
double Cylinder::Area(void) const
{
double TwoPiR = 2.0 * Cylinder::pi * this->mRadius;
return (TwoPiR * this->mRadius) + (TwoPiR * this->mHeight);
}
// used to claculate and return volume
double Cylinder::Volume(void) const
{
return Cylinder::pi * this->mRadius * this->mRadius * this->mHeight;
}
#include "Shape.h"
// init static data memeber
int Shape::mObjectCount = 0;
// constructor
Shape::Shape(void)
:mNoOfSides(1)
{
++Shape::mObjectCount;
}
// desstructor
Shape::~Shape(void)
{
--Shape::mObjectCount;
}
// used to set mNoOfSides member
void Shape::setNoOfSides(const int & setVal)
{
if (setVal > 0)
{
this->mNoOfSides = setVal;
}
// otherwise just leave set to original value
}
// used to return current value of mNoOfSides member
int Shape::getNoOfSides() const
{
return this->mNoOfSides;
}
// used to return current value of mObjectCount static member
int Shape::getObjectCount()
{
return Shape::mObjectCount;
}
/* no longer required to be implemented now that it is a
pure virtual function
// used to calculate and return area
double Shape::Area(void) const
{
return 0.0;
}
*/
// used to calculate and return volume
double Shape::Volume(void) const
{
return 0.0;
}
OK I figured it out now. I forgot to provide a constructor implementation for my TwoDimensionalShapes and ThreeDimensionalShapes classes. Silly mistake.
Related
Im practicing memberwise assignment in C++, where you can set the values of one object to another object of the same class. The idea of the program is to initialize a rectangle object with some values and create another rectangle object but assign the value of the first into the second.
Its giving me an error, which is posted below, and I can't figure out what it is and its driving me nuts lol
This is my Rectangle.h
#ifndef RECTANGLE_H
#define RECTANGLE_H
class Rectangle {
private:
double length;
double width;
public:
Rectangle(double, double);
double getLength() const;
double getWidth() const;
};
Rectangle::Rectangle(double l, double w) {
length = l;
width = w;
}
double Rectangle::getWidth() const { return width; }
double Rectangle::getLength() const { return length; }
#endif
This is my Rectangle.cpp
#include <iostream>
#include "rectangle.h"
using namespace std;
int main()
{
Rectangle box1(10.0, 10.0);
Rectangle box2;
cout << "box1's width and length: " << box1.getWidth() << ", " << box1.getLength() << endl;
cout << "box2's width and length: " << box2.getWidth() << ", " << box2.getLength() << endl;
box2 = box1;
cout << "box1's width and length: " << box1.getWidth() << ", " << box1.getLength() << endl;
cout << "box2's width and length: " << box2.getWidth() << ", " << box2.getLength() << endl;
return 0;
}
This is the error when I compile.
skipper~/Desktop/Programming/Memberwise: g++ rectangle.cpp
rectangle.cpp:7:12: error: no matching constructor for initialization of
'Rectangle'
Rectangle box1(10.0, 10.0);
^ ~~~~~~~~~~
./rectangle.h:4:7: note: candidate constructor (the implicit copy constructor)
not viable: requires 1 argument, but 2 were provided
class Rectangle {
^
./rectangle.h:4:7: note: candidate constructor
(the implicit default constructor) not viable: requires 0 arguments, but 2
were provided
1 error generated.
EDIT: This is how I was able to make it work. I moved everything into rectangle.cpp and gave the constructor default arguments.
EDITED rectangle.cpp
#include <iostream>
using namespace std;
class Rectangle {
private:
double length;
double width;
public:
//Rectangle();
Rectangle(double = 0.0, double = 0.0);
double getLength() const;
double getWidth() const;
};
int main()
{
Rectangle box1(10.0, 10.0);
Rectangle box2;
cout << "box1's width and length: " << box1.getWidth() << ", " << box1.getLength() << endl;
cout << "box2's width and length: " << box2.getWidth() << ", " << box2.getLength() << endl;
box2 = box1;
cout << "box1's width and length: " << box1.getWidth() << ", " << box1.getLength() << endl;
cout << "box2's width and length: " << box2.getWidth() << ", " << box2.getLength() << endl;
return 0;
}
Rectangle::Rectangle(double l, double w) {
length = l;
width = w;
}
double Rectangle::getWidth() const { return width; }
double Rectangle::getLength() const { return length; }
The only changes I made were giving default arguments to my user-defined constructor. However, it wasn't able to work when the changes were in rectangle.h. However, when I moved the class and member function definitions to rectangle.cpp it was able to work. So, I got the program to work but I didn't address the real issue, which is when the class and member function definitions are in rectangle.h, it won't compile.
If anyone has faced this problem and has found a solution to this, please let me know how you did it. Thanks :)
In the line
Rectangle box2; // no default constructor, error
you are trying to invoke the default constructor of Rectangle. The compiler does not generate such a default constructor anymore, because your Rectangle has a user defined constructor that takes 2 parameters. Therefore, you need to specify the parameters, like
Rectangle box2(0,10);
The error I get when compiling your code is:
Rectangle.cpp:8:15: error: no matching function for call to 'Rectangle::Rectangle()'
Rectangle box2;
A solution is to create a default constructor for Rectangle, since it is not automatically generated anymore due to your user defined one:
Rectangle(); // in Rectangle.h
Rectangle::Rectangle(){} // in Rectangle.cpp (or Rectangle::Rectangle() = default; in C++11)
Another solution (and the preferable one, since it doesn't leave the data un-initialized) is to assign default arguments to your existing constructor.
Rectangle::Rectangle(double l = 0, double w = 0); // only in Rectangle.h
In this way, you make your class Default-Constructible.
A compiler generated default constructor is only generated if you have no defined constructors. You define a constructor, so if you want a default constructor you have to provide it yourself. Probably the easiest (arguably) is to provide it by using default arguments in your two argument constructor:
Rectangle(double l=0, double w=0)
Also you should use the inline keyword as shown below or you may find you get linker errors:
inline Rectangle::Rectangle(double l, double w) {
length = l;
width = w;
}
inline double Rectangle::getWidth() const { return width; }
inline double Rectangle::getLength() const { return length; }
I am trying to call a function in another class. I need to use the surface area function or the information that was stored in it from the previous class for another class. How would I go about that?
I have already tried HalfOpenCylinder::surfaceArea() and HalfOpenCylinder.surfaceArea() and neither worked.
//surface area function that I want to use for other class
double HalfOpenCylinder::surfaceArea(double height, double pi) {
double surfaceArea = (2 * pi * radius * height) + (pi * pow(radius, 2));
return surfaceArea;
}
To call a function from another class you need to first create an object (instance) of that class.
Using that object you can call a particular function
eg:
#include <iostream>
using namespace std;
class Student
{ // defining class
public:
int id;
void add(){
int x=1;
int y=2;
int z=x+y;
cout<<z<<endl;
}
};
int main() {
Student s1; // creating object of class
s1.id=20;
s1.add() // calling function of that class
return 0;
}
I have written a script that shows you how you can
"call a function in another class"
and
"use the surface area function or the information that was stored in it from the previous class for another class".
This is a script with many examples in it. It uses an updated version of your surfaceArea() method (method being the term since the function is defined from within a class). I have also included what output the script produces at the very bottom of the script.
You can copy and past this entire code segment into a C++ compiler and it should work for you. I compiled and tested it in Visual Studio 2015 Community. I went to new project, and created a "Win32 Console Application" in the C++ category.
// ConsoleApplication10.cpp : Defines the entry point for the console application.
//
// This class example was created to answer kittykoder's question on StackOverflow.
// Both of these need to be included
#include "stdafx.h"
#include <iostream>
// We need the std namespace
using namespace std;
// Here I am defining a struct so that you can easily take all the values out of the
// HalfOpenCylinder class at once, and even make a new Cylinder object with the values by
// using the struct in one of the two HalfOpenCylinder class constructors.
struct CylinderValues
{
public:
CylinderValues(double radius, double height, double surfaceArea) {
this->radius = radius;
this->height = height;
this->surfaceArea = surfaceArea;
}
__readonly double radius;
__readonly double height;
__readonly double surfaceArea;
};
// This is the class I saw in your example. Since it is named
// HalfOpenCylinder, I decided to treat it like an
// instantiatable object class, both because it makes sense name wise,
// and based on the context you provided in your question.
class HalfOpenCylinder
{
public:
// Pi is always 3.14, so there is no reason to make it a passable parameter
// like in your example. Thus I have made it a constant. It's a static constant because
// of the static function I've placed in this class to help in answering your question.
static const float pi;
// I have encapsulated the variables that make up this
// class's objects behind methods so that the surface area can be
// updated every time the radius or height values are changed.
double GetRadius() { return radius; }
void SetRadius(double value) { radius = value; UpdateSurfaceArea(); }
double GetHeight() { return height; }
void SetHeight(double value) { height = value; UpdateSurfaceArea(); }
double GetSurfaceArea() { return surfaceArea; }
// You can make a HalfOpenCylinder object with this constructor
HalfOpenCylinder(double radius, double height) {
this->radius = radius;
this->height = height;
UpdateSurfaceArea();
}
// You can use another HalfOpenCylinder object to make a new HalfOpenCylinder object using
// this constructor.
HalfOpenCylinder(CylinderValues values) {
radius = values.radius;
height = values.height;
surfaceArea = values.surfaceArea;
}
// This will return the struct needed to use the constructor just above this comment.
CylinderValues CopyValues() {
return CylinderValues(radius, height, surfaceArea);
}
// Here is your surface area calculation from your question
static double CalculateSurfaceArea(double radius, double height) {
return (2 * pi * radius * height) + (pi * pow(radius, 2));
}
private:
// Here are the values you wanted to be able to access from another class.
// You can access them using the methods above for getting and setting. The
// surfaceArea value is automatically recalculated if you change either the
// radius or height variable's values.
double radius;
double height;
double surfaceArea;
// This method is here so that HalfOpenCylinder objects can use the
// Surface area calculation. I could have copied and pasted the calculation
// code here to avoid calling the static method, but then I would be writing code
// more than need be. This way, you can update one and the other will be correct.
void UpdateSurfaceArea() {
surfaceArea = CalculateSurfaceArea(radius, height);
}
};
// This is honestly just here because the compiler yelled at me for defining a static
// constant inside a non-static class. Could'a gotten away with it in C#. Thank you compiler.
const float HalfOpenCylinder::pi = 3.141592;
// This is called a function since it is outside of any class (although,
// that is one of the few differences between functions and methods.
// Methods being, functions defined inside classes)
void ThisIsAFunction() {
cout << "This is the text from the function named: ThisIsAFunction";
}
// This class is just here to show you how to call functions and methods from inside classes
class CallFunctionAndMethodTester
{
public:
void MethodInsideTheClass() {
cout << "The below is printed from a function called in a class: \n";
// Here, I am calling a function from inside a class
ThisIsAFunction();
cout << "\n\nThe below is printed from a static method called in a class: \n";
// Here, I am calling a static method from inside a class
cout << HalfOpenCylinder::CalculateSurfaceArea(14.5, 50.5);
// Here, I am making an object instance from inside a class
HalfOpenCylinder bobTheCylinder(1.5, 5.4);
cout << "\n\nThe below is printed from an object's method called in a class: \n";
// Here, I am calling an object's method from inside a class
cout << bobTheCylinder.GetRadius();
}
};
// Ok. We made it. THIS main function is where we will use and
// test the classes we have made above.
int main() {
// Make a new cylinder object. No pointer, so it will be destroyed when the computer
// reads past main (which is the end of this program anyways).
cout << "Cylinder 1 Values: \n";
HalfOpenCylinder cylinder1(5.0, 10.0);
cout << cylinder1.GetRadius();
cout << "\n"; // <--just makin' a newline here
cout << cylinder1.GetHeight();
cout << "\n";
cout << cylinder1.GetSurfaceArea();
cout << "\n\n"; // <--just makin' two newlines here
// Change the object's height. The surface area updates automatically.
cout << "Cylinder 1 new surface area once Height is changed: \n";
cylinder1.SetHeight(20.5);
cout << cylinder1.GetSurfaceArea();
cout << "\n\n";
// Make a second Cylinder using the first cylinder's values.
cout << "Cylinder 2 Values: \n";
HalfOpenCylinder cylinder2(cylinder1.CopyValues());
cout << cylinder2.GetRadius();
cout << "\n";
cout << cylinder2.GetHeight();
cout << "\n";
cout << cylinder2.GetSurfaceArea();
cout << "\n\n";
// Here I'm using the static CalculateSurfaceArea function to use the surface area
// method without having to make a new HalfOpenCylinder object.
cout << HalfOpenCylinder::CalculateSurfaceArea(5.0, 10.0);
cout << "\n\n";
// Here I am making an object of type CallFunctionAndMethodTester so that I can call
// the method inside it that is using my example of how to call functions and methods
// from within classes.
CallFunctionAndMethodTester tester;
cout << "Everything printed to the console after this line is printed using functions and methods that are called from inside classes. \n\n";
tester.MethodInsideTheClass();
int meh;
cin >> meh;
return 0;
}
/* Here is the output of this code when the program runs:
Cylinder 1 Values:
5
10
392.699
Cylinder 1 new surface area once Height is changed:
722.566
Cylinder 2 Values:
5
20.5
722.566
392.699
Everything printed to the console after this line is printed using functions and methods that are called from inside classes.
The below is printed from a function called in a class:
This is the text from the function named: ThisIsAFunction
The below is printed from a static method called in a class:
5261.38
The below is printed from an object's method called in a class:
1.5
*/
I have implemented different classes derived from an abstract class and each one has different methods. The problem is that I have to declare the object only at runtime, so I have to create a pointer to the base class and I can't use the methods of each derived class.
I have created an example to explain better what I mean:
#include <iostream>
using namespace std;
class poligon
{
public:
double h, l;
void setPoligon(double h, double l) {
this->h = h;
this->l = l;
}
virtual double GetArea() = 0;
virtual void GetType() = 0;
};
class triangle : public poligon
{
double GetArea() { return l*h / 2; }
void GetType() { cout << "triangle" << endl; }
double GetDiag() { return sqrt(l*l + h*h); }
};
class rectangle : public poligon
{
double GetArea() { return l*h; }
void GetType() { cout << "rectangle" << endl; }
};
void main()
{
poligon* X;
int input;
cout << "1 for triangle and 2 for rectangle: ";
cin >> input;
if (input == 1)
{
X = new triangle;
}
else if (input == 2)
{
X = new rectangle;
}
else
{
cout << "Error";
}
X->h = 5;
X->l = 6;
X->GetType();
cout << "Area = " << X->GetArea() << endl;
if (input == 2)
{
cout << "Diangonal = " << X->GetDiag() << endl; // NOT POSSIBLE BECAUSE " GetDiag()" IS NOT A METHOD OF "poligon" CLASS !!!
}
}
Obviously the method X->GetDiag() at the end of the main can't be used because it is not a method of the "poligon" class.
Which is the correct implementation of a program with this logic?
Introduce a method in the base class
virtual bool boHasDiagonal(void) =0;
Declare unconditionally in base class:
virtual double GetDiag();
Implement it differently in both derived classes:
virtual bool boHasDiagonal(void) {return true;} // rectangle
virtual bool boHasDiagonal(void) {return false;} // triangle
Change output line:
if (X->boHasDiagonal())
{cout << "Diangonal = " << X->GetDiag() << endl;}
For a nice touch of paranoia (a healthy state of mind for a programmer in my opinion), use concept by Gluttton of a default implementation of GetDiag(), which signals an error (as in his answer here) .
For the case of many poligons, I like the proposal by Rakete1111 in the comment.
Define method in the base class which define implementation throws exception:
class poligon
{
public:
virtual double GetDiag()
{
throw std::logic_error ("Called function with inappropriate default implementation.");
}
};
In class that has meaningful implementation override it:
class rectangle : public poligon
{
double GetDiag() override
{
return diagonale;
}
};
Usage:
int main () {
try {
X->GetDiag();
}
catch (...) {
std::cout << "Looks like polygon doesn't have diagonal." << std::endl;
}
}
You can use dynamic_cast.
dynamic_cast<triangle*>(X)->GetDiag();
Note that you already have a bug: You only create a triangle if input == 1, but you get the diagonal if input == 2. Also, the above is not really safe, because dynamic_cast can return nullptr if the conversion is invalid.
But it would be better to check whether dynamic_cast succeeds, then you could also drop the input == 2 check:
if (triangle* tri = dynamic_cast<triangle*>(X))
std::cout << "Diagonal = " << tri->GetDiag() << '\n';
Use dynamic casting to check if the base class' pointer is actually a triangle, like this:
int main()
{
...
if(triangle* t = dynamic_cast<triangle*>(X))
std::cout << "Triangle's diagonal = " << t->GetDiag() << std::endl;
return 0;
}
PS: I assume that your example is just a draft, since it has some bugs.
You use dynamic_cast to access subclass-methods.
It returns nullptr if it is not derived from the class. This is called down cast, as you are going down the class-tree:
triangle* R = dynamic_cast<triangle*>(X);
if(R) {
cout << "Diagonale = " << R->GetDiag() << '\n';
};
Edit: You can put the declaration in the first line into the if-condition, which goes out of scope outside the if-statement:
if(triangle* R = dynamic_cast<triangle*>(X)) {
cout << "Diagonale = " << R->GetDiag() << '\n';
};
if(rectangle* R = ...) {...}; // reuse of identifier
If you want to allow, that multiple subclasses have the GetDiag function you can inherit from the poligon-class and another diagonal-class. The diagonal-class only defines the GetDiag function and has not really to do with the polygon-class:
class polygon {
// stays the same
};
class diagonal {
virtual double GetDiag() = 0;
};
class triangle : public polygon, public diagonal {
// body stays the same
};
And like above, you access the methods via casting with dynamic_cast but this time you cast to type diagonal. This time it is side cast, because poligon has nothing to do with diagonal, so you are going sideways in the tree.
polygon diagonal
| | |
| |_____________|
| |
| |
rectangle triangle
As others have said, you can use dynamic_cast to change the static type in your program, add a method to the base-class with a pseudo implementation or use some form of type-switching. However, I would consider all these answers as signs of a design flaw in your program and would reject the code. They all encode assumptions about the types existing in your program into the code and pose a maintenance burden. Imagine adding new types of shapes to your program. You then have to search and modify all the places you dynamic_cast your objects.
I think your example hierarchy is wrong in the first place. When you declare a base-class for ploygons, and derive triangles from it, the whole purpose of polymorphism is to be able to treat similar objects identically. So anything that is not common behavior (not implementation) is put in the base-class.
class poligon
{
public:
double h, l;
void setPoligon(double h, double l) {
this->h = h;
this->l = l;
}
virtual double GetArea() = 0;
virtual void GetType() = 0;
};
class triangle : public poligon
{
double GetArea() { return l*h / 2; }
void GetType() { cout << "triangle" << endl; }
double GetDiag() { return sqrt(l*l + h*h); }
};
You explicitly say that I can replace any instance of polygon with an instance of triangle everywhere in your program. This is the the Liskov substitution principle. What about circles? They don't have height and length. Can you use a rectangle everywhere you expect a polygon? Currently you can, but polygons can have more edges, be self-intersecting etc. I cannot add a new edge to a rectangle, otherwise it would be a rectangle anymore.
There are some solutions, but as it is a design question, the solution depends on what you want to do with the objects.
A downcast is usually a sign of a bad design and is rarely needed in practice.
I can't see why it is needed in this particular case. You have discarded the information about which type you have for no reason. An alternative could be:
void printDiagonal(const triangle& tri)
{
std::cout << "Diangonal = " << tri.GetDiag() << std::endl;
}
void process(poligon& p)
{
p.h = 5;
p.l = 6;
p.GetType();
std::cout << "Area = " << p.GetArea() << std::endl;
}
int main()
{
int input;
std::cout << "1 for triangle and 2 for rectangle: ";
std::cin >> input;
if (input == 1)
{
triangle tri;
process(tri);
printDiagonal(tri);
}
else if (input == 2)
{
rectangle rect;
process(rect);
}
else
{
std::cout << "Error\n";
}
}
Live demo.
I am very new to programming, and am near the end of this program, but cannot quite finish the last detail, which I have been stuck on. I am attempting to switch what shape pointer *sp is pointing to, and it seems to me that what I am doing should work, since rectangle and circle both are shapes; however, when I compile, only the value of the color changes. The area of the circle prints instead of the area of the rectangle and the perimeter prints 0. Any help would be greatly appreciated!
#include <iostream>
#include <string>
using namespace std;
double const pi = 3.1519;
class shape {
public:
shape() {};
shape(string);
virtual double getCircumference() {
return 0;
};
virtual double getPerimeter() {
return 0;
};
virtual double getArea() {
return 0;
};
string getColor();
protected:
string color;
};
string shape::getColor() {
return color;
}
class circle : public shape {
public:
circle(double r, string c) {
radius = r;
color = c;
};
double getArea();
double getCircumference();
private:
double radius;
};
double circle::getCircumference() {
return pi * radius * 2;
}
double circle::getArea() {
return pi * radius * radius;
}
class rectangle:public shape {
public:
rectangle(double w, double l, string c) {
width = w;
length = l;
color = c;
};
double getArea();
double getPerimeter();
private:
double length;
double width;
};
double rectangle::getPerimeter() {
return width * 2 + length * 2;
}
double rectangle::getArea() {
return length * width;
}
void change(shape *sp, shape *sp1) {
*sp = *sp1;
}
int main() {
circle mary(3.2, "Green");
shape *sp = new circle(4.5, "Yellow");
cout << "Circle #1 is " << mary.getColor() << endl;
cout << "Circle #1 has an area of " << mary.getArea() << endl;
cout << "Circle #1 has a circumference of " << mary.getCircumference() << endl << endl;
cout << "Circle #2 is " << sp->getColor() << endl;
cout << "Circle #2 has an area of " << sp->getArea() << endl;
cout << "Circle #2 has a circumference of " << sp->getCircumference() << endl << endl;
shape *sp1 = new rectangle(1.0, 2.1, "Red");
change(sp, sp1);
cout << "Rectangle #1 is " << sp->getColor() << endl;
cout << "Rectangle #1 has an area of " << sp->getArea() << endl;
cout << "Rectangle #1 has a perimeter of " << sp->getPerimeter() <<endl<< endl;
}
It’s important to keep in mind what is meant by various different ways of using pointers. In your program, sp refers to the pointer itself—that is, a memory location telling the computer where to find an object. The asterisk in *sp is a ‘dereference’ operator; it takes a pointer and gives you the thing that it is pointing to.
With this in mind, your line *sp = *sp1; is saying, ‘take the thing that sp is pointing to, and set it to be equal to the thing that sp1 is pointing to.’ In other words, you are changing the value of the object pointed to by sp, not the value of sp itself. To point sp at the object pointed to by sp1, you need sp = sp1; with no asterisks.
The other thing to bear in mind is that C++ by default passes function arguments by value: when the function is called, the arguments are copied, and the function operates on the copies. This means that the original arguments themselves cannot be changed by a function that works like this. Adding an ampersand to the argument declaration, like void change(shape *&sp, shape *sp1) causes the first argument to be passed by reference: the object operated on by the function is the same object that was passed in by the calling code. This allows the function to change objects passed as arguments, and for those changes to remain after the function has returned.
Sorry for the long answer: I could have given you a few lines that did what you wanted, but I thought you might appreciate an explanation of the reason why things work the way they do.
If you are trying to change the address of pointers, you must pass pointers by reference. Try this:
void change(shape *&sp, shape *&sp1)
A pointer is passed by value even if it's a pointer.
This means that you are actually passing the address by value, so the argument is a copy of the original argument.
Think about
void sum(int a, int b, int result);
void foo() {
int result;
sum(5,10,result);
}
While you expect to be able to store the result into the variable passed to the sum argument you won't be able to do it since result is passed by value and hence copied. Every modification you do to result inside the method will be local to the method.
That's exactly the same thing, a pointer is nothing more than an address, if you pass it by value then a copy of the address is passed but every modification to the local variable is just local.
That's why you must use references if you want to be able to modify their values, exactly as every other variable, so you would have
void sum(int a, int b, int& result);
void change(shape*& shape1, shape*& shape2);
This, under the hood, will pass the address to the variable which stores the address (a sort of shape**) so the function is able to know where the original argument is located and modify it directly.
I am getting this annoying error and I don't know why =( !
This is the question , I solved it but I am having a problem with the constructor.
Write a program that defines a class called Circle that includes radius (type double) as data members. Provide a set and a get function
for this data member. Ensure that the value entered by the user is
valid and correct (greater than zero).
Include function members: a.function member that compute and return Diameter of the circle b.function member that compute and
return Circumference of the circle c.function member that compute and
return Area of the circle d.function member that Display all
information of the circle e.constructor that initializes the data
member. If the radius is not valid (i.e. less than zero) set it to
zero.
the error I am facing :
error C2512: 'Circle' : no appropriate default constructor available
this is my code :
#include <iostream>
using namespace std;
class Circle
{
public:
Circle(double);
void setRadius(double);
double getRadius();
void Display();
double Diameter(double);
double Circumference(double);
double Area(double);
private:
double radius;
};
Circle::Circle(double radio)
{
setRadius(radio);
}
void Circle::setRadius(double ra)
{
if (ra < 0)
{
radius = 0;
}
else
radius = ra;
}
double Circle::getRadius()
{
double rado;
cout << "Enter the Radius:\n";
cin >> rado;
setRadius(rado);
return radius;
}
double Circle::Diameter(double rad)
{
return 2*rad;
}
double Circle::Area(double radi)
{
return 3.14 * radi * radi;
}
double Circle::Circumference(double radiu)
{
return 2 * 3.14 * radiu;
}
void Circle::Display()
{
cout << "The Radius of the circle is: \n";
cout << radius;
cout << "\nThe Diameter of the circle is: \n";
cout << Diameter(radius);
cout << "\nThe Circumference of the circle is: \n";
cout << Circumference(radius);
cout << "\nThe Area of the circle is: \n";
cout << Area(radius);
cout << endl;
}
int main()
{
Circle C;
C.getRadius();
C.Display();
return 0;
}
This line invokes a constructor with no arguments (known as default constructor):
Circle C;
The only constructor you have defined is:
Circle(double);
Hopefully this should point you in the right direction.
A default constructor is one without any parameters. Normally, it is provided for you. But if you explicitly define any other constructor, then it is not. So you have to define it yourself, or not use it. You are using it when you create an object in main, like this:
Circle C;
So, either define a default constructor, or don't use it.
Well, then add one :)
Circle() : radius(0.0) {}
You should define a constructor with no parameters called default constructor. You can initialize related members to the default values.
Circle::Circle()
{
radius = 0.0
}