So I have a base class (Shape) and three derived classes, Circle, Rectangle and Square (Square is derived from Rectangle) I'm attempting to implement operator<< which just calls the correct display function for what called it. However, I don't think I have the syntax correct. Here's a snippet--where have I gone wrong?
class Shape
{
public:
Shape(double w = 0, double h = 0, double r = 0)
{
width = w;
height = h;
radius = r;
}
virtual double area() = 0;
virtual void display() = 0;
protected:
double width;
double height;
double radius;
};
ostream & operator<<(ostream & out, const Shape & s)
{
s.display(out);
return out;
}
class Rectangle : public Shape
{
public:
Rectangle(double w, double h) : Shape(w, h)
{
}
virtual double area() { return width * height; }
virtual void display()
{
cout << "Width of rectangle: " << width << endl;
cout << "Height of rectangle: " << height << endl;
cout << "Area of rectangle: " << this->area() << endl;
}
};
You're calling display like this:
s.display( out );
But display is defined as:
vritual void display() = 0;
The function was declared and defined taking no parameters. It should take a reference to std::ostream as a parameter:
virtual void display(std::ostream &) = 0;
It should also be a const method as you're passing in a const object through the operator << overload:
virtual void display(std::ostream &) const = 0;
Don't forget that in the definition of display you should be writing to the ostream object, not specifically std::cout.
Here is a compiling program on Ideone.
You have a number of problems here. Firstly, let's deal with the printing problem:
ostream & operator<<(ostream & out, const Shape & s)
Here, you're passing a const Shape. This means you can only call const methods on the s you pass in. However, you haven't marked any of the methods in the base (or derived) class as const. Neither area nor display should change the state of the object. Secondly, you're trying to call s.display(out), that is, passing an ostream& to display. The function signature you have doesn't reflect this. So putting that all together we get:
virtual double area() const = 0;
virtual void display(ostream& out) const = 0;
You've also got some other problems - a base class that doesn't declare a virtual destructor. If you're planning on using a class polymorphically, it must have a virtual destructor:
virtual ~Shape() { }
You also need to amend your methods in the derived class:
double area() const { return width * height; }
void display(ostream& out) const
{
out << "Width of rectangle: " << width << endl;
out << "Height of rectangle: " << height << endl;
out << "Area of rectangle: " << area() << endl;
}
Note that display in Rectangle was always printing to cout beforehand.
You almost got it right, here is the working solution:
#include <iostream>
using std::cout;
using std::endl;
using std::ostream;
class Shape
{
public:
Shape(double w = 0, double h = 0, double r = 0)
{
width = w;
height = h;
radius = r;
}
virtual ~Shape() {} // Recommended!
virtual double area() const = 0;
virtual void display(ostream & out) const = 0;
protected:
double width;
double height;
double radius;
};
ostream & operator<<(ostream & out, const Shape & s)
{
// Since `s` is `const`, then `display` method should be `const` too.
s.display(out);
return out;
}
class Rectangle : public Shape
{
public:
Rectangle(double w, double h) : Shape(w, h)
{
}
virtual double area() const { return width * height; }
virtual void display(ostream & out) const
{
// Since `display` method is `const`, then `area` method should be
// `const` too.
out << "Width of rectangle: " << width << endl;
out << "Height of rectangle: " << height << endl;
out << "Area of rectangle: " << this->area() << endl;
}
};
void main() {
Rectangle r(1, 2);
cout << r << endl;
}
Please, pay attention to the const qualifiers which enforce const-correctness of class methods. I've added some useful comments so that you can follow the logic smoothly. Take it as a rule of thumb, if the method does not modify class members, then you should declare it const.
Related
The constructor of class "Circle" allows the radius to be specified via a parameter, while it is not possible to create objects of the Circle type without specifying the parameter. Also, automatic conversion of real numbers into Circle objects must not be allowed. The Set method, which does the same thing as a constructor, should also be supported, except that it allows the radius of an already created object to be changed later.
The Cylinder class constructor requires two parameters that represent the base radius and the height of the roller, respectively. Instances of this class also cannot be created without specifying the mentioned information. It should also support the "Set" function, which does the same thing as a constructor, except that it allows you to modify an already created object.
Both classes must have other methods (listed in code).
I need to use class Circle inside class Cylinder to enable calculating volume, area, and other functions.
#include <cmath>
#include <iostream>
class Circle {
double radius;
public:
Circle(double r);
void Set(double r);
double GetRadius() const;
double GetPerimeter() const;
double GetArea() const;
void Scale(double s);
void Print() const;
};
class Cylinder {
Circle baze;
double height;
public:
Cylinder(double r_baze, double h);
void Set(double r_baze, double h);
Circle GetBaze() const;
double GetRadiusOfBaze() const;
double GetHeight() const;
double GetArea() const;
double GetVolume() const;
void Scale(double s);
void Print() const;
};
int main() {
return 0;
}
Circle::Circle(double r) {
radius = r;
}
void Circle::Set(double r) {
radius = r;
}
double Circle::GetRadius() const { return radius; }
double Circle::GetPerimeter() const { return 2 * 4 * atan(1) * radius; }
double Circle::GetArea() const { return radius * radius * 4 * atan(1); }
void Circle::Scale(double s) {
radius *= s;
}
void Circle::Print() const {
std::cout << "R= " << GetRadius() << " O= " << GetPerimeter()
<< " P= " << GetRadius();
}
Cylinder::Cylinder(double r_baze, double h) {
baze.GetRadius() = r_baze;
height = h;
}
void Cylinder::Set(double r_baze, double h) {
baze.GetRadius() = r_baze;
height = h;
}
Circle Cylinder::GetBaze() const { return baze; }
double Cylinder::GetRadiusOfBaze() const { return baze.GetRadius(); }
double Cylinder::GetHeight() const { return height; }
double Cylinder::GetArea() const {
return baze.GetArea() * 2 + baze.GetPerimeter() * height;
}
double Cylinder::GetVolume() const { return baze.GetArea() * height; }
void Cylinder::Scale(double s) {
baze.GetRadius() *= s;
height *= s;
}
void Cylinder::Print() const {
std::cout << "R= " << baze.GetRadiusOfBaze() << " H= " << height
<< " P= " << GetArea() << " V= " << GetVolume();
}
I'm new to objected-oriented programming concept. Could you help me to understand where I'm making mistakes?
I cannot compile this, because I get errors:
57 : no matching function for call to ‘Circle::Circle()’
14: note: candidate: ‘Circle::Circle(double)’
14: note: candidate expects 1 argument, 0 provided
3: note: candidate: ‘constexpr Circle::Circle(const Circle&)’
3: note: candidate expects 1 argument, 0 provided
62, 70, 91 : lvalue required as left operand of assignment
Cylinder::Cylinder(double r_baze, double h) {
baze.GetRadius() = r_baze;
height = h;
}
In your Cylinder class, when your constructor is called, baze is implicitly initialized with a default constructor that does not exist.
You want to use an initializer list to handle that initialization, at which point the code inside your Cylinder constructor becomes unnecessary.
Cylinder::Cylinder(double r_baze, double h)
: baze(r_baze), height(h) {
}
Alternatively, you could provide functionally a default constructor for your Circle class, and then Set the radius in Cylinder's constructor, but that's more work.
Circle::Circle(double r=0.0) {
radius = r;
}
Cylinder::Cylinder(double r_baze, double h) {
baze.Set(r_baze);
height = h;
}
Also...
Please note that GetRadius returns a double and cannot be assigned to, so you will get an error on that line of code.
This question already has answers here:
What is object slicing?
(18 answers)
Closed 5 years ago.
Hey guys here is some code I am going to run, issue is it doesn't work the way I intend to. I am unable to figure out what's wrong with it. I am c++ noob please help.
#include <iostream>
#include <cmath>
#include <stdexcept>
using namespace std;
/**
* Super class
*/
class Shape
{
protected:
int _dimensions;
public:
Shape() : _dimensions{0}
{};
Shape(int dims) : _dimensions{dims}
{};
virtual double getArea() {};
// Because some shapes have no volume.
virtual double getVolume() {};
void setDimensions(int dim)
{
this->_dimensions = dim;
};
int getDimensions()
{
return this->_dimensions;
};
};
/**
* Extended classes
*/
class TwoDimensionalShape : public Shape
{
public:
TwoDimensionalShape() : Shape{2}
{};
// This should throw an error
double getVolume() {
throw logic_error("This shape ain't got area!");
};
};
class ThreeDimensionalShape : public Shape
{
public:
ThreeDimensionalShape() : Shape{3} {};
};
/**
* Final Concrete classes extending extended classes
*/
class Circle : public TwoDimensionalShape
{
protected:
double _radius;
public:
Circle(double r) : _radius{r}
{};
double getArea()
{
// pi*r^2
return M_PI * pow(_radius, 2);
}
};
class Square : public TwoDimensionalShape
{
protected:
double _side;
public:
Square(double s) : _side{s}
{}
double getArea()
{
// s^2
return pow(_side, 2);
}
};
class Triangle : public TwoDimensionalShape
{
protected:
double _base, _height;
public:
Triangle(double b, double h) : _base{b}, _height{h}
{};
double getArea()
{
// b*h/2
return _base * _height / 2;
}
};
class Sphere : public ThreeDimensionalShape
{
protected:
double _radius;
public:
Sphere(double r) : _radius{r}
{}
double getArea()
{
cout << 4 * M_PI * pow(_radius, 2) << endl;
return 4 * M_PI * pow(_radius, 2);
}
double getVolume()
{
return (4/3) * M_PI * pow(_radius, 3);
}
};
class Cube : public ThreeDimensionalShape
{
protected:
double _side;
public:
Cube(double s) : _side{s}
{};
double getArea()
{
// surface area = 6*a^2
return 6 * pow(_side, 2);
}
double getVolume()
{
// a^3
return pow(_side, 3);
}
};
class Tetrahedron : public ThreeDimensionalShape
{
protected:
double _side;
public:
Tetrahedron(double s) : _side{s}
{};
double getArea()
{
// sqrt(3)*a^2
return sqrt(3) * pow(_side, 2);
}
double getVolume()
{
// a^3/6sqrt(2)
return pow(_side, 3) / (6 * sqrt(2));
}
};
int main()
{
Shape arr[2];
arr[0] = Circle{10};
arr[1] = Sphere{10};
// This one is accessing the right method.
cout << "Area of circle: " << arr[0].getArea() << endl;
// This one should access the parent, but accesses the grand parent!
// even if it is overridden in parent.
cout << "Volume of circle: " << arr[0].getVolume() << endl;
// Both of these are accessing methods on grand parent rather than their own!!
cout << "Area of sphere: " << arr[1].getArea() << endl;
cout << "Volume of sphere: " << arr[1].getVolume() << endl;
return 0;
}
I don't know why the array methods keep accessing the grand parent functions in the last three lines, but the right method on the first.
You are experiencing Object Slicing. The portion of your code below does that:
Shape arr[2];
arr[0] = Circle{10};
arr[1] = Sphere{10};
Each of the assignments above invokes the copy assignment operator of Shape and slices off objects of the subclass. You can achieve your intention by using references or pointers:
std::unique_ptr<Shape> arr[2];
arr[0] = std::make_unique<Circle>(10);
arr[1] = std::make_unique<Sphere>(10);
This is a case of object slicing. You need to put your objects as pointers, preferably as std::unique_ptr<> into your array - or again preferably a std::vector<>
Try this:
#include <memory>
#include <vector>
// ...
int main()
{
std::vector<std::unique_ptr<Shape>> vec(2);
vec[0] = std::make_unique<Circle>(10);
vec[1] = std::make_unique<Sphere>(10);
// This one is accessing the right method.
cout << "Area of circle: " << vec[0]->getArea() << endl;
// This one should access the parent, but accesses the grand parent!
// even if it is overridden in parent.
cout << "Volume of circle: " << vec[0]->getVolume() << endl;
// Both of these are accessing methods on grand parent rather than their own!!
cout << "Area of sphere: " << vec[1]->getArea() << endl;
cout << "Volume of sphere: " << vec[1]->getVolume() << endl;
return 0;
}
#include<iostream>
#include<string>
#include<cmath>
using namespace std;
class Polygon {
public:
Polygon() {}
Polygon(int point, float length) {
mPoint = point;
mLength = length;
}
~Polygon() {}
virtual void calcPerimeter() {
cout << "Perimeter: " << mLength * mPoint;
}
virtual void calcArea() {
cout << "Area: " << sqrt(3) * pow(mLength, 2) / 4;
}
protected:
int mPoint;
double mLength;
};
class Rectangle : public Polygon {
public:
Rectangle() {}
Rectangle(int point, float length):mPoint(4), mLength(4 * length){}
~Rectangle() {}
void calcPerimeter() override {
cout << "Perimeter: " << mLength;
}
void calcArea() override {
cout << "Area: " << mLength * mLength;
}
};
int main() {
Polygon pol;
Rectangle rec(4, 10);
cout << "--- Polygon class---" << endl;
pol.calcPerimeter();
pol.calcArea();
cout << "---Rectangle class---" << endl;
rec.calcPerimeter();
rec.calcArea();
return 0;
}
I learned that if the protected part of the parent class is inherited as public, it is used like a private in the child class. By the way
Rectangle (int point, float length): mPoint (4), mLength (4 * length) {}
In this part, I get the error that mPoint and mLength are not non-static data members or the base class of Reactangle. If it's private, can't I use it like that in a class ??
If I'm misunderstanding, I hope you can tell me what's wrong. Thanks for reading.
You're right about being able to use protected data in the derived class. However, that's not the problem here.
In
Rectangle (int point, float length): mPoint (4), mLength (4 * length) {}
you are initializing the fields, and that can only be done once, in the initializer list of the constructor of the class in which they are declared (Polygon).
You could assign them in the body of the constructor:
Rectangle (int point, float length)
{
mPoint = 4;
mLength = 4 * length;
}
but better is just to call the base class constructor and let it do its job:
Rectangle (int point, float length):Polygon (4, 4 * length) {}
All of this begs the question why you're passing point to the Rectangle constructor when you don't use it.
Also, it's widely regarded as bad practice to have protected fields (protect methods are okay) because once they are protected they are accessible all the way down the inheritance hierarchy. Better to keep them private and provide protected set methods.
I want to make an object of DataArea class in Area class and initialize data in main function. But the only way my code works is by initializing data in Area class.
Also, I do not know if I have made the object correctly or not. Please guide me. My code is below:
#include<iostream>
using namespace std;
class DataArea
{
public:
int radius, length, width, base, heigth;
DataArea(int l, int w, int b, int h, int r)
{
length = l;
width = w;
radius = r;
heigth = h;
base = b;
}
};
class Area
{
public:
DataArea* s = new DataArea(3, 4, 5, 6, 7);
float AreaCirle()
{
return 3.142 * s->radius * s->radius;
}
float AreaRectangle()
{
return s->length * s->width;
}
float AreaTraingle()
{
return (s->base * s->heigth) / 2;
}
};
class print_data : public Area
{
public:
void print()
{
cout << "Area of Circle is: " << AreaCirle() << endl;
cout << "Area of Rectangle is: " << AreaRectangle() << endl;
cout << "Area of Traingle is: " << AreaTraingle() << endl;
}
};
int main()
{
//DataArea da(3, 4, 5, 6, 7);
print_data m;
m.print();
}
Your DataArea is basically absolute if you do not use it outside of Area class. Similarly, print_data class can be replaced by an operator<< overload.
Following is the updated code, in which the comments will guide you through.
#include <iostream>
// DataArea (optionally) can be the part of Area class
struct DataArea /* final */
{
float length, width, base, height, radius;
DataArea(float l, float w, float b, float h, float r)
: length{ l } // use member initializer lists to initlize the members
, width{ w }
, base{ b }
, height{ h }
, radius{ r }
{}
};
class Area /* final */
{
DataArea mDataArea; // DataArea as member
public:
// provide a constructor which initialize the `DataArea` member
Area(float l, float w, float b, float h, float r)
: mDataArea{ l, w, b, h, r } // member initializer
{}
// camelCase naming for the functions and variables
// mark it as const as the function does not change the member
float areaCirle() const /* noexcept */
{
return 3.142f * mDataArea.radius * mDataArea.radius;
}
float areaRectangle() const /* noexcept */
{
return mDataArea.length * mDataArea.width;
}
float areaTraingle() const /* noexcept */
{
return (mDataArea.base * mDataArea.height) / 2.f;
}
// provide a operator<< for printing the results
friend std::ostream& operator<<(std::ostream& out, const Area& areaObject) /* noexcept */;
};
std::ostream& operator<<(std::ostream& out, const Area& areaObject) /* noexcept */
{
out << "Area of Circle is: " << areaObject.areaCirle() << "\n";
out << "Area of Rectangle is: " << areaObject.areaRectangle() << "\n";
out << "Area of Traingle is: " << areaObject.areaTraingle() << "\n";
return out;
}
int main()
{
// now construct the Area object like this
Area obj{ 3, 4, 5, 6, 7 };
// simply print the result which uses the operator<< overload of the Area class
std::cout << obj;
}
Output:
Area of Circle is: 153.958
Area of Rectangle is: 12
Area of Traingle is: 15
It seems to me that Area class is surplus for what you are trying to achieve. You should probably put methods directly in DataArea class. Then you can create as many of DataArea objects as you like...
Like this:
class DataArea
{
public:
int radius, length, width, base, heigth;
DataArea(int l , int w , int b , int h , int r )
{
length = l;
width = w;
radius = r;
heigth = h;
base = b;
}
float AreaCirle()
{
return 3.142 * radius * radius;
}
float AreaRectangle()
{
return length * width ;
}
float AreaTraingle()
{
return (base * heigth)/2;
}
};
int main(int argc, char **argv)
{
DataArea area1 (1,2,3,4,5);
DataArea area2 (8,2,3,4,5);
std::cout << area1.AreaCirle() << std::endl;
std::cout << area2.AreaCirle() << std::endl;
}
The reason why you are probably having trouble to understand the concept:
You're defining a class and instantiating an object. Sometimes these terms are used interchangeably, but in this case, this is an important distinction.
If you would like for your methods to operate on some other class, that you should make methods that accept that class as an argument. Otherwise, it is unnecessary complex.
I dont understand the diffrence between Polymorphism and Inheritance... They Litterarly do the same thing...
Simple Example Of Polymorphism:
class shape {
public:
void setValues(int height_, int width_) {
height = height_, width = width_;
}
protected:
int height, width;
private:
};
class rectangle :public shape, public ThreeDView{
public:
int area() {
return(shape::height*shape::width);
}
float threeDArea() {
return(((shape::height*shape::width)/2)*(std::cos(Z_LENGTH)));
}
};
class ThreeDView{
public:
void setZLength(int value) {
Z_LENGTH = value;
}
int setCompact(bool ans) {
compact = ans;
}
float getZLength() {
return Z_LENGTH;
}
bool getCOMPACT() {
return compact;
}
protected:
float Z_LENGTH;
bool compact;
private:
unsigned char ZCHAR = 'Z';
};
class triangle :public shape {
public:
int area() {
return((shape::height * shape::width) / 2);
}
};
int main(){
rectangle rect2;
triangle trng2;
shape *poly = &rect2;
shape *poly2 = &trng2;
poly->setValues(2,3);
poly2->setValues(5,4);
std::cout << "AREA : " << trng1.area() << "AREA RECT : \n" <<rect1.area() << std::endl;
}
Above example translated to Inheritance:
class shape {
public:
void setValues(int height_, int width_) {
height = height_, width = width_;
}
protected:
int height, width;
private:
};
class rectangle :public shape, public ThreeDView{
public:
int area() {
return(shape::height*shape::width);
}
float threeDArea() {
return(((shape::height*shape::width)/2)*(std::cos(Z_LENGTH)));
}
};
class triangle :public shape {
public:
int area() {
return((shape::height * shape::width) / 2);
}
};
int main(){
rectangle rect2;
triangle trng2;
rect2.setValues(2,3);
trng2.setValues(5,4);
std::cout << "AREA : " << trng1.area() << "AREA RECT : \n" <<rect1.area() << std::endl;
}
Please tell me diffrence. Honestly i dont even see the use of Polymorphism! Thanks for helping!
Here's a version of your first example, that actually uses polymorphism:
#include <iostream>
#include <string>
class shape
{
public:
void setValues(int height_, int width_)
{
height = height_;
width = width_;
}
virtual int area() = 0; // This is needed for polymorphism to work
virtual std::string name() = 0;
protected:
int height;
int width;
};
class rectangle : public shape
{
public:
int area()
{
return height * width;
}
std::string name()
{
return "Rectangle";
}
};
class triangle :public shape
{
public:
int area()
{
return height * width / 2;
}
std::string name()
{
return "Triangle";
}
};
void print_area(shape& poly)
{
std::cout << poly.name() << ' ' << poly.area() << '\n';
}
int main()
{
rectangle rect;
triangle trng;
rect.setValues(2, 3);
trng.setValues(5, 4);
print_area(rect);
print_area(trng);
}
The first big change is that I declare the virtual function area in the shape class. For polymorphism to work, the functions must be declared in the base class as virtual. The "assignment" to 0 is simply telling the compiler that it's an abstract function, and the child-classes must override that function.
The second big change is that I use a function to print the area, one that only takes a reference to the base shape class. You must use references or pointers to the base class for polymrphism to work, not use the actual objects directly like in your example.
This works as expected.