I am trying to print with a function from a function in a derived class with a function from the base class within it and I am not exactly sure if I should be
how I can print out both information from the Shape toString function and the Rectangle toString function.
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
class Shape
{
public:
Shape(double w, double h);
string toString();
private:
double width;
double height;
};
Shape::Shape(double w, double h)
{
width = w;
height = h;
}
string Shape::toString()
{
stringstream ss;
ss << "Width: " << width << endl;
ss << "Height: " << height << endl;
return ss.str();
}
class Rectangle : public Shape
{
public:
Rectangle(double w, double h, int s);
string toString();
private:
int sides;
};
string Rectangle::toString()
{
//
// Implement the Rectangle toString function
// using the Shape toString function
Shape::toString();
cout << toString();
stringstream ss;
ss << "Sides: " << sides << endl;
return ss.str();
}
// Use the constructor you created
// for the previous problem here
Rectangle::Rectangle(double w, double h, int s)
:Shape(w, h)
{
sides = s;
}
The only parts that can be manipulated in the problem are the sections that come after the comments
I think the problem is with this line:
cout << toString();
since it is going to recursively call itself and eventually you will run out of stack and get the runtime error.
your implementation should be:
string Rectangle::toString()
{
// Implement the Rectangle toString function
// using the Shape toString function
stringstream ss;
ss << Shape::toString();
ss << "Sides: " << sides << endl;
return ss.str();
}
Also consider making this method const and virtual in the case you want polymorphism to work properly.
Related
In the process of trying to understand and use classes and methods, I have been trying to create a class with private values that uses a method to alter those values. I create a program that requests input from a user (a length and width) and creates a "rectangle" from those values (it just stores the values they input as if it was a rectangle.) For some reason, the method I used doesn't alter the private length and width values in the class. I used the .h file to create the class and the .cpp to create the function that gets input with the main.cpp being used to call the function. For the sake of simplicity, I removed the input validation section of the code in the .cpp file because it does not affect the class values. Can you help me find my mistake?
My .h file with the class in it:
#pragma once
#include <iostream>
using namespace std;
class Rectangle
{
private:
double length;
double width;
public:
Rectangle()
{
length = 0;
width = 0;
}
Rectangle(double a)
{
length = a;
width = a;
}
Rectangle(double l, double w)
{
length = l;
width = w;
}
void SetLenWid(double l, double w)
{
if (l == w)
{
Rectangle (l);
cout << "You have created a square with sides equal to " << length << endl;
}
else
{
Rectangle (l, w);
cout << "You have created a rectangle of length = " << length << " and width = " << width << endl;
}
}
};
The Rectangle.cpp file:
#include "Rectangle.h"
#include <iostream>
void getInput()
{
double l, w;
cout << "Enter the length: ";
cin >> l;
cout << "Enter the width ";
cin >> w;
Rectangle init;
init.SetLenWid(l, w);
}
Finally, my main.cpp:
#include "Rectangle.h"
#include "Rectangle.cpp"
#include <iostream>
using namespace std;
int main()
{
getInput();
return 0;
}
Sorry for the very long-winded question!
Rectangle(l, w); doesn't do what you think it does. It creates a temporary rectangle, which is then destroyed immedately.
Rectangle(l); also doesn't do what you expect. It's equivalent to Rectangle l;, which creates a rectangle named l using the 0-argument constructor.
You want *this = Rectangle(l, w);, or just assign to the fields directly.
I am currently experiencing a problem that I just can't seem to wrap my head around why it would be occurring.
In my (Unsplit)program I've created a class that defines an entity object and is able to handle its creation and variables just fine (as I've tested before adding
std::string getName(Entity)const;
std::string getType(Entity)const;
int getDamage(Entity)const;
int getHealth(Entity)const;
But when I do... Even though they are already declared publicly in the class and I am fully able to call Initialize(); Attack(); and PrintStats(); just fine, it doesn't see the other four and therefor are not able to be called.
#include <iostream>
#include <string>
#include <math.h>
#include <stdlib.h> /* srand, rand */
#include <time.h> /* time */
using namespace std;
class Entity
{
public:
Entity() { // default constructor
name = "Human";
type = "Normal";
damage = 1;
health = 100;
}
void printStats();
void Initialize(string, string, int, int); //transformer or setting function
void Attack(Entity&); //observer or getter function
std::string getName(Entity)const;
std::string getType(Entity)const;
int getDamage(Entity)const;
int getHealth(Entity)const;
private://data members and special function prototypes
std::string name;
std::string type;
int damage;
int health;
};
void summonEnemy(Entity&);
int main () {
/* initialize random seed: */
srand (time(NULL));
Entity Player;//declaring new class objects
Entity Enemy;//declaring new class objects
Player.Initialize("Player", "Normal", 10, 90);
summonEnemy(Enemy);
return 0;
}
void summonEnemy(Entity &target) {
target.Initialize("Enemy", "Normal", floor(rand() % 20 + 1), floor(rand() % 100));
cout << "An " << getType(target) << " type " << getName(target) << " has appeared with " <<
getHealth(target) << "HP and can do " << getDamage(target) << " damage.";
}
Error message:
error:'getType' Was not defined in this scope.
error:'getName' Was not defined in this scope.
error:'getHealth' Was not defined in this scope.
error:'getDamage' Was not defined in this scope.
Cut off some code to narrow it down such that only what could be the cause of the problem is showing... But honestly its probably something simple that I am not seeing. Any help appreciated.
You are not calling them correctly. They are members of the Entity class, not standalone functions. Remove the Entity parameters from them, as they already have an implicit Entity *this parameter, and then call them like this:
class Entity
{
public:
Entity(); // default constructor
...
std::string getName() const;
std::string getType() const;
int getDamage() const;
int getHealth() const;
...
};
Entity::Entity()
{
Initialize("Human", "Normal", 1, 100);
}
std::string Entity::getName() const
{
return name;
}
std::string Entity::getType() const
{
return type;
}
int getDamage() const
{
return damage;
}
int getHealth() const
{
return health;
}
void summonEnemy(Entity &target)
{
target.Initialize("Enemy", "Normal", floor(rand() % 20 + 1), floor(rand() % 100));
cout << "An " << target.getType() << " type " << target.getName() << " has appeared with " <<
target.getHealth() << "HP and can do " << target.getDamage() << " damage.";
}
getType is a member function of Entity, so you need to call it on an Entity object:
target.getType();
In the class, you could implement it as:
class Entity {
...
std::string getType() const { return type; }
...
};
The same is true for your other three setters.
I'm working with my code and I faced this problem. I want to put 3 different classes data in single vector, so I created base class vector. It look like this :
std::vector <Video*> vid_list;
When I read the file I push data in this vector using one of the derived class constructors like that :
vid_list.push_back(new Official_Music_Video(video_title, video_time,
Date(y,m,d), num_of_views));
so I want to display this data on the screen, but my base class only got methods for
std::string title;
double time;
Date date_of_release;
but not for int number_of_views. I heard that if I wanna use derived class getter method I have to use upcasting so I tried to make this
void views (Video& v) {
v.get_views();
}
and then in my display method
void Official_Music_Video::display_info(std::vector <Video*>& vid_list){
Official_Music_Video ofc;
for (unsigned int i = 0; i < vid_list.size(); i++){
cout << vid_list[i]->get_title() << " " << vid_list[i]->get_time()
<< " " << vid_list[i]->write_year_to_file() << "-" <<
vid_list[i]->write_month_to_file() << "-" << vid_list[i]-
>write_day_to_file () << endl;
cout << "This video viewed " << vid_list[i].views(ofc) << " times"
<< endl;
}
}
But it's not working. Can you help me understand where I made mistake and what's wrong ?
If all three of your derived classes have a "number_of_views" method, put it in the base class as well, and problem solved. If not, then your code is nonsensical. What do you expect to happen when you put an "Unofficial_Music_Video" into the vector, and run your loop over it?
If you really need to add per-type behavior to the class, consider what you actually want to accomplish. Do you need users of Video to be able to query "number_of_views", despite the fact that field doesn't exist for all subtypes? Maybe you just want to access a human-readable description of the statistics? If that's the case, it might make the most sense to add a "virtual std::string StatsSummary()" method to Video, and make subclasses implement it as required.
You might want to move some of the implementation to the base class or so, but this is something that could help you finding the solution:
#include <vector>
#include <string>
#include <iostream>
class Date // for demo only
{
public:
Date(int y, int, int m, int d)
: y(y) , m(m), d(d) {}
int y;
int m;
int d;
};
class Video
{
public:
virtual std::string get_title() = 0;
virtual int get_time() = 0;
virtual int write_year_to_file() = 0;
virtual int write_month_to_file() = 0;
virtual int write_day_to_file () = 0;
virtual ~Video(){}
virtual void display_info()
{
std::cout << get_title()
<< " " << get_time()
<< " " << write_year_to_file()
<< "-" << write_month_to_file()
<< "-" << write_day_to_file ()
<< std::endl;
}
};
class VideoWithViewCount
: public Video
{
public:
virtual int views() = 0;
virtual void display_info()
{
Video::display_info();
std::cout << "This video viewed " << views() << " times" << std::endl;
}
};
class Official_Music_Video : public VideoWithViewCount
{
public:
Official_Music_Video(std::string _video_title, int _video_time, Date _date, int _Num_of_views)
: d(_date)
, time(_video_time)
, Num_of_views(_Num_of_views)
, video_title(_video_title)
{}
virtual int get_time() override {return time; };
virtual int write_year_to_file() override { return d.y; } // better call them get...
virtual int write_month_to_file() override {return d.m; }
virtual int write_day_to_file () override { return d.d; }
virtual int views() override {return Num_of_views; };
private:
Date d;
int time;
int Num_of_views;
std::string video_title;
};
class Other_Video : public Video
{
public:
Other_Video(std::string _video_title, int _video_time, Date _date)
: d(_date)
, time(_video_time)
, video_title(_video_title)
{}
virtual int get_time() override {return time; };
virtual int write_year_to_file() override { return d.y; }
virtual int write_month_to_file() override {return d.m; }
virtual int write_day_to_file () override { return d.d; }
private:
Date d;
int time;
std::string video_title;
};
int main(int,char**)
{
std::vector <Video*> vid_list;
// could also use unique_ptr or shared_ptr from #include <memory> in vector as follows:
// std::vector <unique_ptr<Video> > vid_list;
// std::vector <shared_ptr<Video> > vid_list;
// fill video vector
// vid_list.push_back(new Official_Music_Video(video_title, video_time, Date(y,m,d), num_of_views));
for (auto v : vid_list) // when using unique_ptr remember to use "const auto&" instead of "auto"
{
v->display_info();
}
return 0;
}
I've been working on a program that calculates the volume of a box, using classes to help me understand how to use classes. As part of the program I want to convert my objects length,width and height into a string to display the dimensions of the box. When I run the code from my main file it crashes. When I run it from the class file I get "could not convert Box::length from double to std::string. How can I fix the conversion error?
#include <iostream>
#include <stdexcept>
#include <sstream>
#include <iomanip>
#include <string>
using namespace std;
class Box
{
public:
double length;//length of the box
double height;//height of the box
double width;//with of the box
Box(): length(1), height(1), width(1){}
//Parameterized Constructor
Box(double length, double width, double height);
double getVolume(void);
//Mutators
void setLength(double leng);
void setWidth(double wid);
void setHeight(double hei);
//Acessors
string toString() const;
string getLength();
string getWidth();
string getHeight();
};//end class
//member function definitions
double Box::getVolume(void)//get volume will cal and output the volume when called
{
return length * width * height;
}
void Box::setLength(double leng)
{
const double MIN_LENGTH = 0.1;//constants for min/max for range check and out_of_range exception
const double MAX_LENGTH = 99;
if (length > MAX_LENGTH || length < MIN_LENGTH)
{
stringstream strOut;//declare string stream
strOut << "Length is out of range. Length must be between" << MIN_LENGTH << " and " << MAX_LENGTH << ".";//error msg
throw out_of_range(strOut.str());
}
else
{
length = leng;// if length is within range, store it
}
}
string Box::getLength()
{
return length;
}
void Box::setWidth(double wid)
{
const double MIN_WIDTH = 0.1;//constants for min/max for range check and out_of_range exception
const double MAX_WIDTH = 99;
if (length > MAX_WIDTH || length < MIN_WIDTH)
{
stringstream strOut;//declare string stream
strOut << "Width is out of range. Width must be between" << MIN_WIDTH << " and " << MAX_WIDTH << ".";//error msg
throw out_of_range(strOut.str());
}
else
{
width = wid;// width is in range, store it
}
}
string Box::getWidth()
{
return width;
}
void Box::setHeight(double hei)
{
const double MIN_HEIGHT = 0.1;//constants for min/max for range check and out_of_range exception
const double MAX_HEIGHT = 99;
if (length > MAX_HEIGHT || length < MIN_HEIGHT)
{
stringstream strOut;//declare string stream
strOut << "Height is out of range. Height must be between" << MIN_HEIGHT << " and " << MAX_HEIGHT << ".";//error msg
throw out_of_range(strOut.str());
}
else
{
height = hei;// height is in range, store it
}
}
string Box::getHeight()
{
return height;
}
string Box::toString() const
{
stringstream strOut;
strOut << "Length: " << getLength() << endl
<< "Width: " << getWidth() << endl <<
"Height: " << getHeight() << endl;
return strOut;
}
This compile error is occurring at the return statements of your getWidth, getHeight, getLength functions. This is because the you declared them to return a string but instead returned a width, height, and length which are doubles. The compiler sees that there is no automatic conversion from double to string.
To fix this you only need to fix the return type of the function from string to double:
double getLength();
double getWidth();
double getHeight();
I noticed one more error:
doubletostring.cpp:104:25: error: reference to non-static member function must be called
strOut << "Length: " << getLength << endl
And similar errors in the toString method. Simply convert them to function calls by adding () at the end:
strOut << "Length: " << getLength() << endl
Your class definition says getLength() will return a string, however your getLength() function actually returns width, which is a double. You probably meant to convert length to a string before you return it.
You could use the to_string() function in the string library, and change your getLength() to
return to_string(length)
I am creating a vector that contains pointers to a base class. In this vector I'm dynamically storing pointers to derived classes which contain some member variables, one of them being a string variable name.
#include "stdafx.h"
#include <iostream>
#include <vector>
#include <string>
#include <cstdlib>
bool hasDirection = false;
bool hasDiameter = false;
int direction;
float diameter;
int starDimension = 0;
int animalDimension = 0;
int fishDimension = 0;
class MovingObject
{
protected:
std::string name;
int direction;
float diameter;
int dimension;
float movingSpeed;
public:
std::string getName(){ return name;};
int getDirection(){ return direction;};
float getDiameter(){ return diameter;};
float getMovingSpeed(){ return movingSpeed;};
int getDimension(){ return dimension;};
void setName(std::string v){ name = v;};
void setDirection(int d){ direction = d;};
void setDiameter(float f){ diameter = f;};
void setMovingSpeed(float s){ movingSpeed = s;};
void setDimension (int d){ dimension = d;};
virtual void PrintContents()=0;
};
static std::vector<MovingObject*> data;
class starObject : public MovingObject
{
public:
void PrintContents()
{
std::cout << "(" << getName() << "," << getDiameter() << "," << getDirection() << ")";
}
};
class animalObject : public MovingObject
{
public:
void PrintContents()
{
std::cout << "(" << getName() << "," << getDiameter() << "," << getDirection() << ")";
}
};
class fishObject : public MovingObject
{
public:
void PrintContents()
{
std::cout << "(" << getName() << "," << getDiameter() << "," << getDirection() << ", [" << getDimension() << "], " << getMovingSpeed() << ")";
}
};
I later set all these member variables inside a main function. The problem is when I try to output the contents of the member variables, all of them show up except for the string name.
Now, I've checked to make sure that the string gets set before calling the PrintContent() method, and it shows that the value is in the vector. However, when I debug through the code, the value is no longer there, instead containing an empty string.
Could someone with better c++ knowledge explain to me why this is happening? This is the main class:
int main()
{
std::string type;
Reader reader;
while (!std::cin.eof())
{
try
{
std::string type;
std::cin >> type;
if (type =="int")
{
reader.ReadDirection();
}
else if (type =="float")
{
reader.ReadDiameter();
}
else if (type == "string")
{
std::string name;
std::cin >> name;
if (hasDirection && hasDiameter)
{
int dimension;
if (diameter > 0 && diameter < 10)
{
//fish
fishObject fish;
fish.setName(name);
fish.setDiameter(diameter);
fish.setDirection(direction);
dimension = fishDimension;
fishDimension += 50;
fish.setDimension(dimension);
fish.setMovingSpeed(0.1);
data.push_back(&fish);
}
else if (diameter >= 10 < 500)
{
//animal
animalObject animal;
animal.setName(name);
animal.setDiameter(diameter);
animal.setDirection(direction);
dimension = animalDimension;
animalDimension += 800;
animal.setDimension(dimension);
animal.setMovingSpeed(5.0);
data.push_back(&animal);
}
else if (diameter >=500)
{
//star
starObject star;
star.setName(name);
star.setDiameter(diameter);
star.setDirection(direction);
dimension = starDimension;
starDimension += 5000;
star.setDimension(dimension);
star.setMovingSpeed(30.0);
data.push_back(&star);
}
}
else
{
throw (IncompleteData(name));
}
}
}
catch (IncompleteData e)
{
std::cerr << "No diameter or direction given for object " << e.objectName << "\n";
}
}
The objects you push to the data vector are local because they are declared inside if/else blocks (see the declarations of fish and animal).
When you push the address of such an object to the vector, it will continue to point to the local object, which ceases to exist at the end of the local scope. You need to create objects that live beyond the local scope. One way of doing this is to create copies of the local objects on the heap and push those to the vector:
data.push_back(new fishObject(fish));
Of course this means that you get a memory leak unless you make sure you explicitly delete the elements of the vector some time before the end of the program. The usual recommendation to avoid having to think of this is to use a vector of std::unique_ptr<MovingObject> instead of a vector of naked pointers.