How can I use method of which parameter is vector? - c++

#include <iostream>
#include <iomanip>
#include <cmath>
#include <vector>
#include <algorithm>
using namespace std;
class Shape{
protected:
int _r;
int _w;
int _h;
public:
Shape(double r) : _r(r) {}
Shape(double w, double h) : _w(w), _h(h) {}
virtual double area(vector<Shape *>){
cout << "shape:: area " << endl;
return _r;
}
};
class Circle : public Shape{
public:
Circle(double r) : Shape(r) {}
double area(vector<Shape *>) { return _r*_r*atan(1)*4.0; }
};
class Triangle : public Shape{
public:
Triangle(double s) : Shape(s) {}
double area(vector<Shape *>) { return sqrt(3) * pow(_r, 2) / 4; }
};
class Rectangular : public Shape{
public:
Rectangular(double w, double h) :Shape(w, h) {}
double area(vector<Shape *>) { return _w * _h ;}
};
int main()
{
int n;
char info;
int value;
int value2;
double sum;
vector<Shape > collection;
vector<int> answer;
sum = 0;
cin >> n;
for(int i = 0 ; i < n; i++)
{
cin >> info;
if (info == 'C')
{
cin >> value;
Circle c(value);
collection.push_back(c);
}
else if (info == 'R')
{
cin >> value;
cin >> value2;
Rectangular r(value, value2);
collection.push_back(r);
}
else
{
cin >> value;
Triangle t(value);
collection.push_back(t);
}
}
for (int i = 0; i < n ; i++)
{
sum += collection[i].area(&collection[i]);
}
cout << sum << endl;
}
As you can see , I used an abstract class Shape, and the three concrete class , Circle, Rectangular, Triangle.
And I wanna sum areas of all shapes. such as
First input represents how many shapes we have to calculate. C for circles, R for rectangle, and T for regular triangles.
And I want to override function "area" of which parameter is vector.
But my error is
How can I solve this no viable conversion from 'std::__1::__vector_base<Shape, std::__1::allocator >::value_type'
#include <iostream>
#include <iomanip>
#include <cmath>
#include <vector>
#include <algorithm>
using namespace std;
class Shape{
protected:
int _r;
int _w;
int _h;
public:
Shape(double r) : _r(r) {}
Shape(double w, double h) : _w(w), _h(h) {}
virtual double area(vector<Shape *>) = 0;
};
class Circle : public Shape{
public:
Circle(double r) : Shape(r) {}
double area(vector<Shape *>) { return _r*_r*atan(1)*4.0; }
};
class Triangle : public Shape{
public:
Triangle(double s) : Shape(s) {}
double area(vector<Shape *>) { return sqrt(3) * pow(_r, 2) / 4; }
};
class Rectangle : public Shape{
public:
Rectangle(double w, double h) :Shape(w, h) {}
double area(vector<Shape *>) { return _w * _h ;}
};
int main()
{
int n;
char info;
int value;
int value2;
double sum;
vector<Shape*> collection;
vector<int> answer;
sum = 0;
cin >> n;
for(int i = 0 ; i < n; i++)
{
cin >> info;
if (info == 'C')
{
cin >> value;
Circle c(value);
collection.push_back(&c);
}
else if (info == 'R')
{
cin >> value;
cin >> value2;
Rectangle r(value, value2);
collection.push_back(&r);
}
else
{
cin >> value;
Triangle t(value);
collection.push_back(&t);
}
}
for (int i = 0; i < n ; i++)
{
sum += collection[i]->area(collection);
}
cout << fixed << setprecision(2) << sum << endl;
}
I changed and fix!

Polymorphism does not work with concrete classes!
By declaring vector<Shape> collection;, you declare a vector of Shape, not of Circle, Triangle or Rectangular. You probably want collection to be of type vector<Shape*> to be able to utilize polymorphism.
Another issue with your code is that you don't pass collection, which is of type vector<Shape>, but collection[i] which just is of type Shape.
This would probably also explain your error, since your compiler most likely wants to parse Shape into vector<Shape*> since that's type of the argument of area. This is not possible, and therefore probably causes your compiler error.
Also, if you want to pass just collection, you'd have to make sure the types are matching. vector<Shape> is not implicitly convertable into vector<Shape*>

Related

Having Trouble with Inheritance in C++

I'm having a little trouble with inheritance.
Main.cpp
#include <iostream>
#include "Shapeclass.h"
using namespace std;
int main() {
int shapecount, shapetype[200],i,height[200], width[200];
string name;
cout << "AREA CALULATOR";
cout << "Enter Your Name ";
cin >> name;
cout << "Enter the amount of Shapes you want to calculate Area of: ";
cin >> shapecount;
Shape *p1[200];
cout << "Enter 1 for Circle Enter 2 for Rectangle and 3 for Triangle";
for ( i = 0; i < shapecount; i++)
{
cin >> shapetype[i];
}
for ( i = 0; i < shapecount; i++)
{
if (shapetype[i]==1)
{
cout << "Enter Radius of circle";
cin >> width[i];
p1[i] = new sphere(width[i]);
}
else if (shapetype[i] == 2) {
cout << "Enter width of rectangle";
cin >> width[i];
cout << "Enter height of rectangle";
cin >> height[i];
}
else if (shapetype[i] == 3) {
cout << "Enter base of triangle";
cin >> width[i];
cout << "Enter height of triangle";
cin >> height[i];
}
}
}
Shapeclass.h
#include <iostream>
using namespace std;
class Shape
{
protected:
double area ;
int height, width;
string nama;
void virtual calculate() = 0;
public:
void display() {
calculate();
}
private:
};
class sphere :public Shape {
void calculate(double height, double width) {
}
};
class rectangle :public Shape {
public:
rectangle(int width1, int height1)
{
width = width1;
height = height1;
}
void calculate(double height, double width) {
area = height * width;
}
};
class triangle :public Shape {
public:
triangle(int width1, int height1)
{
width = width1;
height = height1;
}
void calculate(double height, double width) {
area = height * width*0.5;
}
};
class sphere :public Shape {
public:
sphere(int width1)
{
width = width1;
}
void calculate(double width) {
area = width*width*3.14 ;
}
};
I have no idea why it says object of abstract class type "sphere" is not allowed. Specifically line 42.
I'm trying to initialize pointer array objects but it doesn't want to work.
I'm trying to send the width of the sphere to the class but I can't initialize the value of width with the pointer array. To be more specific.
The Shape::calculate() method is declared as pure virtual:
void virtual calculate() = 0;
So, it must be overloaded in derived classes to have them considered by the compiler as concrete ones you'd able to call.
In your case, the overloaded method would be responsible to determine the area of each shape according to its kind and update the instance property.
for example:
void rectangle::calculate() {
area = height * width;
}
and
void triangle::calculate() {
area = height * width * 0.5;
}
would compute the right area for given shapes.
Shape* s1 = new triangle(w, h);
s1->calculate(); // effective call to triangle::calculate()
Shape* s2 = new rectangle(w, h);
s2->calculate(); // effective call to rectangle::calculate()

How to Make Function using OOP

Anyone can help me to make function using OOP? How to be able to make the function of finding the average of height of students with OOP?
class Person
{
//data members
private:
string name;
int age;
int height;
float weight;
//member functions
public:
void setPerson(string n, int a, int h, float w)
{
name=n;
age=a;
height=h;
weight=w;
}
void setName(string n) { name=n; }
void setAge(int a) { age=a; }
void setHeight(int h) { height=h; }
void setWeight(int w) { weight=w; }
string getName() {return name;}
int getAge() {return age;}
int getHeight() {return height;}
float getWeight() {return weight;}
};
int main()
{
Person p[100];
int x;
cin >> x;
string name;
int age;
int height;
float weight;
for(int i=0; i<x; i++)
{
cin >> name >> age >> height >> weight;
p[i].setName(name);
p[i].setAge(age);
p[i].setHeight(height);
p[i].setWeight(weight);
}
..............
my input are :
3 (number of person)
jason 20 185 70.50 (name age height weight)
emma 19 165 55.55
yerry 25 164 65.10
output :
171.33
Once you have your Persons recorded, it's just a matter of calculating the average height. It should not be a member function of Person, as the class is intended to represent a single Person. An average height is not a property or action taken on/by/to a single Person, so we just calculate it in main().
I've noted changes that I made to your code.
#include <algorithm>
#include <iomanip>
#include <iostream>
#include <string>
#include <vector>
class Person {
// data members
private:
std::string name;
int age;
int height;
float weight;
// member functions
public:
// CHANGE: Change function to constructor
Person(std::string n, int a, int h, float w)
: name(n), age(a), height(h), weight(w) {}
void setName(std::string n) { name = n; }
void setAge(int a) { age = a; }
void setHeight(int h) { height = h; }
void setWeight(int w) { weight = w; }
std::string getName() { return name; }
int getAge() { return age; }
int getHeight() { return height; }
float getWeight() { return weight; }
};
int main() {
std::vector<Person> p; // CHANGE: Switch from C-array to std::vector
int x;
std::cin >> x;
std::string name;
int age;
int height;
float weight;
for (int i = 0; i < x; i++) {
std::cin >> name >> age >> height >> weight;
p.emplace_back(name, age, height,
weight); // CHANGE: Take advantage of vector functionality
// to build Person directly into vector
}
// ADDITION: Calculating average height, std::for_each is subjective here,
// this could have easily been a range-based for loop.
double avgHeight = 0.0;
std::for_each(p.begin(), p.end(), [&avgHeight, size = p.size()](auto person) {
avgHeight += static_cast<double>(person.getHeight()) / size;
});
std::cout << std::fixed << std::setprecision(2) << avgHeight << '\n';
}
Output:
171.33
std::for_each may look goofy, but it's literally just summing heights and dividing by the number of Persons. Like I noted, it could also just be a range-based for loop. I prefer the range-based for loop in this case; I only have std::for_each() because it was a quicker change from my failed attempts at coercing std::reduce to work.
double avgHeight = 0.0;
for (auto i : p) {
avgHeight += static_cast<double>(i.getHeight()) / p.size();
}
The type of i would be better specified as const auto&, but your getters are not marked as const.
You could add a parent struct for Person (call it Individual or something) that has a vector pointer as a member variable. For example, std::shared_ptr<std::vector<double> > Students ( new std::vector<double>() ); The struct would have all the public functions that Person has as pure virtual functions.
Then, add a new void function to Person that derefs Students, and pushes back the height of a new student. Next, you add another function (returning a double or float) that loops through Students to take the sum of the students' heights, and divides it by the size() of the vector.
All Person objects will have pointers to a single Students vector, so every time you push back the height of a new student, it will go to the same place.

Accessing elements of derived class object list throws "read access violation" exception, while list is filled by function

I have a list of derived class objects of 3 types, each contains string and two integers.
#include "pch.h"
#include <iostream>
#include <list>
#include <string>
#include <algorithm>
#include <iterator>
class Shape
{
private:
int x, y;
public:
Shape() {}
Shape(int &x_, int &y_) : x(x_), y(y_) {}
virtual void Draw() {
std::cout << this->x << ", " << this->y << "}\n";
}
};
class Circle : public Shape
{
private:
std::string type;
public:
Circle() {}
Circle(int &x_, int &y_) : Shape(x_, y_) { this->type = "Circle"; }
void Draw() {
std::cout << this->type << ": {";
Shape::Draw();
}
};
class Triangle : public Shape
{
private:
std::string type;
public:
Triangle() {}
Triangle(int &x_, int &y_) : Shape(x_, y_) { this->type = "Triangle"; }
void Draw() {
std::cout << this->type << ": {";
Shape::Draw();
}
};
class Square : public Shape
{
private:
std::string type;
public:
Square() {}
Square(int &x_, int &y_) : Shape(x_, y_) { this->type = "Square"; }
void Draw() {
std::cout << this->type << ": {";
Shape::Draw();
}
};
void FillWithShapes(int n, std::list<Shape*> &ls) {
int x, y, type;
Circle cir;
Triangle tri;
Square sq;
for (int i = 0; i < 10; i++) {
type = rand() % 3;
x = rand() % 100;
y = rand() % 100;
if (type == 0) {
cir = Circle(x, y);
ls.push_back(&cir);
}
else if (type == 1) {
tri = Triangle(x, y);
ls.push_back(&tri);
}
else if (type == 2) {
sq = Square(x, y);
ls.push_back(&sq);
}
}
}
int main()
{
std::list<Shape*> shapes;
FillWithShapes(10, shapes);
std::for_each(shapes.begin(), shapes.end(), [](Shape *s) { s->Draw(); });
}
I'm getting read access violation exception when accessing list elements in lambda:
Exception thrown: read access violation.
s->**** was 0xCCCCCCCC.
But when I put the code from function FillWithShapes straight to main(), it works just fine:
Square: {18, 95}
Triangle: {82, 21}
Circle: {2, 53}
Square: {18, 95}
Triangle: {82, 21}
Square: {18, 95}
Circle: {2, 53}
Circle: {2, 53}
Triangle: {82, 21}
Square: {18, 95}
I have started learning c++ not long ago, so I have no idea what may cause this exception in this case, though I'm probably missing something simple but significant here.
UPD:
Fixed function to create pointers on heap:
void FillWithShapes(int n, std::list<Shape*> &ls) {
int x, y, type;
Circle *cir = new Circle();
Triangle *tri = new Triangle();
Square *sq = new Square();
for (int i = 0; i < 10; i++) {
type = rand() % 3;
x = rand() % 100;
y = rand() % 100;
if (type == 0) {
*cir = Circle(x, y);
ls.push_back(cir);
}
else if (type == 1) {
*tri = Triangle(x, y);
ls.push_back(tri);
}
else if (type == 2) {
*sq = Square(x, y);
ls.push_back(sq);
}
}
}
In your function FillWithShapes, you are creating objects of type Circle, Sqaure etc and pushing those pointers into the vector. Once that function goes out of scope, these pointers are no longer valid.
You could create the objects on the heap and push those in the vector with the burden of de-allocating once done with the vector.
You're filling the list with pointers to variables local to your FillWithShapes() function and stored on the stack. Their lifetime ends after the function returns - so it's reasonable that you get an access violation.
When you hoist the code up to main(), the lifetime of the local variables is now the lifetime of main(), i.e. throughout your program and past your last accesses through the list of shapes - so no violation.
You might want to read: What and where are the stack and heap?

Debugging a Derived Class C++

When I run this code and create an instance of cylinderType by passing four parameters, debugger shows the height I want but, radius=x=y=0. So when I call method printVolume() on this object, it displays '0'.
Am I missing something important with inheritance?
Thank you~
#include <iostream>
using namespace std;
class circleType
{
public:
circleType();
circleType(double r);
double getArea() const;
private:
double radius;
};
class cylinderType : public circleType
{
public:
cylinderType(double h, double r);
void printVolume() const;
private:
double height;
};
int main()
{
cylinderType cylinderA(2, 4);
cylinderA.printVolume();
return 0;
};
circleType::circleType()
{
radius = 0;
};
circleType::circleType(double r)
{
radius = r;
};
double circleType::getArea() const
{
return (3.14 * radius* radius);
};
cylinderType::cylinderType(double h, double r)
{
circleType::circleType(r);
height = h;
};
void cylinderType::printVolume() const
{
cout << (circleType::getArea() * height);
};

Using for_each to call a print function from a list of object

I need to use a for_each function to call the print function of each object in the list of objects shapeList. When I put function output as the final parameter of for_each, I get a "cannot determine which instance of overloaded function "output" is intended.
void output(Point* point)
{
point->print();
}
This is my output function for for_each
for_each(shapeList.begin(), shapeList.end(), output);
The for_each statement
I have looked at other solutions that involve using binds and lambdas, but this is a class assignment and I cannot use those methods.
Any help is greatly appreciated.
#include <iostream>
#include <string>
#include <fstream>
#include <list>
#include <algorithm>
#define sz 12
using namespace std;
class Point
{
private:
int x, y;
public:
Point() { }
Point(int a, int b)
:x(a), y(b) { }
// print function is pure virtual and that makes class Point an abstract class
// a pure virtual function can have prototype only without definition
// an abstract class can't be instantiated
// its derived class must override this function in order to be a real class
virtual void print() const = 0;
};
void Point::print() const
{
cout << "\nPoint: ( "
<< x
<< " , "
<< y
<< " )";
}
///////////////////////////////////////////////////////////////////
class Circle : public Point
{
private:
int radius;
public:
Circle() : Point() { }
Circle(int a, int b, int c)
:Point(a, b), radius(c) { }
virtual void print() const;
};
void Circle::print() const
{
cout << "\nCenter of the Circle is at: ";
Point::print();
cout << "\nRadius of the Circle is: "
<< radius;
}
/////////////////////////////////////////////////////////////////////
class Cylinder : public Circle
{
private:
int height;
char color[sz];
public:
Cylinder() { }
Cylinder(int a, int b, int r, int h, char clr[])
: Circle(a, b, r), height(h)
{ strcpy(color, clr); }
virtual void print() const;
};
void Cylinder::print() const
{
Circle::print();
cout << "\nHeight of Cylinder is: "
<< height
<< "\nColor of Cylinder is: "
<< color
<< endl;
}
void load_list(list<Point*>&, char*); //
void output(Point*&);
///////////////////////////////////////////////////////////////
int main()
{
char clr[10];
list<Point*> shapeList;////
load_list(shapeList, clr);
for_each(shapeList.begin(), shapeList.end(), output);
return 0;
}
void load_list(list<Point*>& ptList, char *ch)
{
char type;
int x, y, r, h;
ifstream infile("shapes.txt");
if (!infile)
{
cout << "\nCan not open input file.";
exit(1);
}
infile >> type;
while (infile)
{
if (type == 'c')
{
infile >> x >> y >> r;
ptList.push_back(new Circle(x,y,r));
}
else if (type = 'l')
{
infile >> x >> y >> r >> h >> ch;
ptList.push_back(new Cylinder(x, y, r, h, ch));
}
infile >> type;
}
}
void output(Point* point)
{
point->print();
}
You declare the function to take a pointer by reference(?) And the implementation takes a pointer.