Why isn't my class using the values I've given it? - c++

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.

Related

Vector data is lost after it goes out of scope

I'm working on a project where I use a forward list and vector together and output their values. The forward list is a list of Frame objects, and the vector is a vector of Display objects. The issue is that after the creation of the objects in InsertFrame(), the values of the vector are lost and essentially become garbage. I can see in the debugger it happens right after the function ends, which leads me to believe it has to do with the variables going out of scope. Here is the main creation class
// Animation.cpp
#include <crtdbg.h>
#include <iostream>
#include <string>
#include <vector>
#include <forward_list>
using namespace std;
#include "Display.h"
#include "Frame.h"
#include "Animation.h"
#include "GPUMemoryDisplay.h"
#include "SystemMemoryDisplay.h"
void Animation::InsertFrame() {
int numDisplays; //for user input of display number
vector <Display*>v; //vector for containing display objects
int p_x; //will contain user input for pixel_x
int p_y; //will contain user input for pixel_y
int p_duration; //will contain user input for duration
int p_type ; //will contain display type as int value
char * p_name; //temp string to contain user input for name
string d_name; //will contain p_name to be passed to display constructor
string frameName; //contains user input for the frame name
string gpu_shader; //contains gpu name if gpu type is selected
int q = 0; //used to count the diplay #
//begin reading user input
cout << "Insert a Frame in the Animation\nPlease enter the Frame filename: ";
cin >> frameName;
cout << "Entering the Frame Displays (the sets of dimensions and durations) " << endl;
cout << "Please enter the number of Displays: ";
cin >> numDisplays;
//display creation loop for # of displays entered
while (numDisplays > 0) {
cout << "Please enter pixel x-width for Display #" << q << " pixel_x:";
cin >> p_x;
cout << "Please enter pixel y-width for Display #" << q << " pixel_y:";
cin >> p_y;
cout << "Please enter the duration for this Display: ";
cin >> p_duration;
cout << "Please enter the name for this Display: ";
cin >> d_name;
cout << "Please enter the type for this display (1 = SystemMemoryDisplay, 2 = GPUMemoryDisplay): ";
cin >> p_type;
p_name = new char[d_name.length() + 1]; //allocate for the size of the name entered
strcpy(p_name, d_name.c_str()); //copy string to char []
if (p_type == 2) {
//input for GPU shader
cout << "Please enter the file name of the associated GPU Shader: ";
cin >> gpu_shader;
Display *gpu_p = new GPUMemoryDisplay(p_x, p_y, p_duration, p_name, gpu_shader);
v.push_back(static_cast <Display*>(gpu_p)); //casting to a display* and pushing onto the vector
numDisplays--;
q++;
}
else {
Display *sm_p = new SystemMemoryDisplay(p_x, p_y, p_duration, p_name);
v.push_back(static_cast <Display*>(sm_p));//casting to a display* and pushing onto the vector
numDisplays--;
q++;
}
cout << "\n";
}
Frame t_frame = Frame(frameName, v); //new frame holds vector which contains displays
//check if forward list is empty
if (frames.empty()) {
cout << "\nThis is the first Frame in the list \n\n";
frames.push_front(t_frame);
}
else {
forward_list <Frame>::iterator it;
int x = 0; // used for size of current forward_list
//iterate forward list to obtain the size
for (it = frames.begin(); it != frames.end(); ++it) {
x++;
}
if (x == 1) {
it = frames.begin();
frames.insert_after(it, t_frame);
}
else {
cout << "There are " << x << " Frame(s) in the list\n" << "Please specify the position, between 0 and " << x << " to insert after : ";
cin >> x; //read in where user wants to put the frame
//iterate to desired position and insert
forward_list <Frame>::iterator it;
it = frames.begin();
while (x != 0 && it != frames.end()) {
it++;
x--;
}
frames.insert_after(it, t_frame);
}
}
}
And the header/cpp files for Frame and Display
// Frame.h
#pragma once
class Frame
{
string fileName;
vector<Display*> displays;
public:
Frame(string s, vector<Display*> d) :fileName(s), displays(d) {}
Frame(const Frame&);
~Frame()
{
vector<Display*>::iterator it;
for (it = displays.begin(); it != displays.end(); it++)
delete *it;
}
friend ostream& operator<<(ostream&, Frame&);
};
#pragma once
// Display.h
class Display
{
protected: // accessible to derived classes
int pixel_x;
int pixel_y;
int duration;
char* name;
public:
Display(int x, int y, int duration, char* name);
Display(const Display&);
virtual ~Display() //makes class abstract, cannot be instantiated, most general class
{
if (name)
delete[]name;
}
virtual int BufferSize() = 0; // overridden function Polymorphic function
friend ostream& operator<<(ostream&, Display&);
};
// Display.cpp
#include <crtdbg.h>
#include <iostream>
#include <string>
#include <vector>
#include <forward_list>
using namespace std;
#include "Display.h"
#include "GPUMemoryDisplay.h"
Display::Display(int x, int y, int d, char* n) :pixel_x(x), pixel_y(y), duration(d), name(n) {
}
Display::Display(const Display& p) {
//copy values from p
pixel_x = p.pixel_x;
pixel_y = p.pixel_y;
duration = p.duration;
size_t len = strlen(p.name);
name = new char[len + 1];
strcpy(name, p.name);
//cout << pixel_x << pixel_y << duration << name;
}
I have two sub classes of Display called GPUMemoryDisplay and SystemMemoryDisplay, however I believe that part of the code is fine as I can see their values stored correctly in the debugger. Included below just in case.
#pragma once
// SystemMemoryDisplay.h
class SystemMemoryDisplay : public Display
{
public:
SystemMemoryDisplay(int x, int y, int duration, char* name) :Display(x, y, duration, name) {};
SystemMemoryDisplay(const SystemMemoryDisplay& RGMD) :Display(RGMD) {}
int BufferSize() { return pixel_x*pixel_y * sizeof(double); }
};
#pragma once
//GPUMemoryDisplay.h
//this is the derived class of display
class GPUMemoryDisplay : public Display
{
string shader;
public:
GPUMemoryDisplay(int x, int y, int duration, char* name, string shader) :Display(x, y, duration, name), shader(shader) {};
GPUMemoryDisplay(const GPUMemoryDisplay& RGPUMD) :shader(RGPUMD.shader), Display(RGPUMD) {}
string GetShader() { return shader; }
int BufferSize() { return pixel_x*pixel_y * sizeof(float); } //this is the overridden function from Display class
};
In summary I have a forward list of frames, each frame can contain a vector of Display objects. However when the InsertFrame() function exits, the display data is lost.
Once your stack-allocated Frame t_frame = Frame(frameName, v); objects go out of scope their destructors are called and will delete all the objects pointed by pointers stored in Frame::displays. You need to implement appropriate copy and / or move constructor and assignment operators that will transfer those pointers correctly. You should use ::std::unique_ptr to keep ownership of allocated objects instead of using raw pointers and deleting them manually and ::std::string to mange strings instead of raw pointer to char. Also putting using namespace std; in-between includes is also no good, if you are going to use it at least place it after includes.

Virtual Functions and Polymorphism - unable to declare object in test class [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Closed 6 years ago.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Improve this question
I've created a program that uses virtual functions and polymorphism to calculate the parameter and area for three different objects: circles, rectangles and right angled triangles. Whenever I try to assign one of the different object classes to the pointer I have in my test class, it says 'Error: expected a type specifier':
shape_ptr = new Rectangle;
Screenshot of error shown
I'm almost sure it's something really simple that I've missed but it's not the inclusion of the header file as I've done that on each class without any mistakes that I can see. Here is my code:
Base Class:
#ifndef SHAPE
#define SHAPE
#include <iostream>
using namespace std;
class Shape {
public:
virtual void compute_area() = 0; // a pure virtual function
virtual void compute_perimeter() = 0; // a pure virtual function
virtual void read_shape_data() = 0; // a pure virtual function
virtual void print_result() { // a virtual function
cout << "The area is " << area << endl;
cout << "The perimeter is " << perim << endl;
}
protected: // protected access specifier
double area, perim;
};
#endif
circle.cpp:
#include "shape.h"
#include <iostream>
using namespace std;
class Circle : public Shape
{
public:
void compute_area() { area = pi * radius; }
void compute_perimeter() { perim = 2 * pi * radius; }
void read_shape_data() {
cout << "Enter radius of the rectangle : ";
cin >> radius;
}
private:
int radius;
double pi = 3.14159265359;
};
rectangle.cpp:
#include "shape.h"
#include <iostream>
using namespace std;
class Rectangle : public Shape
{
public:
void compute_area() { area = width * height; }
void compute_perimeter() { perim = 2 * width + 2 * height; }
void read_shape_data() {
cout << "Enter width of the rectangle : ";
cin >> width;
cout << "Enter height of the rectangle : ";
cin >> height;
}
private:
int width, height;
};
RightTriangle.cpp:
#include "shape.h"
#include <iostream>
using namespace std;
class RightTriangle : public Shape
{
public:
void compute_area() { area = base * height; }
void compute_perimeter() { perim = pow((pow(base, 2) * pow(height, 2)), 2); }
void read_shape_data() {
cout << "Enter base length of triangle : ";
cin >> base;
cout << "Enter height of triangle : ";
cin >> height;
cout <<
}
private:
int radius, base, height;
};
test.cpp (test class):
#include "shape.h"
#include <iostream>
using namespace std;
int main(){
int choice;
Shape* shape_ptr = NULL;
cout << "Enter 1 for circle, 2 for rectangle, 3 for right angled triangle or 0 for exit";
cin >> choice;
switch (choice){
case 1:
shape_ptr = new Rectangle;
break;
}
shape_ptr->read_shape_data();
shape_ptr->compute_area();
shape_ptr->compute_perimeter();
shape_ptr->print_result();
delete shape_ptr;
return 0;
}
Thanks for your time and I'm happy to answer any questions.
The "shape.h" header doesn't automatically know about the definitions of derived classes like Rectangle, so your test file needs to include those headers too:
#include "shape.h"
#include "rectangle.h"
// etc.
#include <iostream>
It looks like you defined your derived classes within .cpp files. Move those declarations into header files, and define them in the .cpp file instead.

Printing from a derived class with a base class function

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.

C++ Nonstatic member referencing must be relative to specific object

This Complex Number program is supposed to take three arguments from a txt document, the first to indicate whether the subsequent two are numbers in polar or rectangular form, and output every complex number given in both rectangular and polar form. Both the header file and source code are shown here. The txt document is in the following format:
p 50 1.2
r 4 0.8
r 2 3.1
p 46 2.9
p 3 5.6
Without declaring the int inputfile() function as static within the class declarations, the build gives an error 'illegal call of non-static member function'.
With the static declaration of the function (shown below), the build gives errors referring to the class members Pfirst, Psecond, Rfirst and Rsecond inside function definition inputfile(), being 'illegal references to non-static members'.
The member declarations cannot then be made static as well because the class would not be able to initialise the parameters within the constructor.
How can I bypass this 'static' problem?
#define Complex_h
class Complex
{
char indicator;
const double pi;
public:
double Pfirst, Psecond, Rfirst, Rsecond;
Complex(char i = 0, double Pf = 0, double Ps = 0, double Rf = 0, double Rs = 0, const double pi = 3.14159265) // with default arguments (= 0)
: indicator(i), Pfirst(Pf), Psecond(Ps), Rfirst(Rf), Rsecond(Rs), pi(pi) {}
~Complex();
void poltorect();
void recttopol();
static int inputfile();
};
#include <iostream>
#include <iomanip>
#include <fstream>
#include <sstream>
#include <string>
#include "Complex.h"
using namespace std;
int Complex::inputfile()
{
ifstream ComplexFile;
ComplexFile.open("PolarAndRectangular.txt");
string TextArray[3];
string TextLine;
stringstream streamline, streamfirst, streamsecond;
while (getline(ComplexFile,TextLine))
{
streamline << TextLine;
for (int j=0; j<3; j++)
{streamline >> TextArray[j];}
streamline.str("");
streamline.clear();
if (TextArray[0] == "r")
{
streamfirst << TextArray[1];
streamfirst >> Rfirst;
streamsecond << TextArray[2];
streamsecond >> Rsecond;
cout << "Complex number in rectangular form is " << Rfirst << "," << Rsecond << endl;
void recttopol();
cout << "Complex number in polar form is " << Pfirst << "," << Psecond << endl;
}
else
{
streamfirst << TextArray[1];
streamfirst >> Pfirst;
streamsecond << TextArray[2];
streamsecond >> Psecond;
cout << "Complex number in polar form is " << Pfirst << "," << Psecond << endl;
void poltorect();
cout << "Complex number in rectangular form is" << Rfirst << "," << Rsecond << endl;
}
streamfirst.str("");
streamfirst.clear();
streamsecond.str("");
streamsecond.clear();
}
ComplexFile.close();
system("pause");
return 0;
}
void Complex::recttopol()
{
Pfirst = sqrt((Rfirst*Rfirst)+(Rsecond*Rsecond));
Psecond = (atan(Rsecond/Rfirst))*(pi/180);
}
void Complex::poltorect()
{
Rfirst = Pfirst*(cos(Psecond));
Rsecond = Pfirst*(sin(Psecond));
}
int main()
{
Complex::inputfile();
system("pause");
return 0;
}
You forgot to create an object of type Complex.
Make your inputfile() method nonstatic and do:
int main()
{
Complex complex; // Object construction.
complex.inputfile();
system("pause");
return 0;
}

C++ simple class declaration program

I got a program to create in C++ in our introduction to C++ class in school. I am doing everything as I got in examples, but still getting errors.
w4x.cpp was given and I have to create Molecule.h and Molecule.cpp. I did that, but I am getting errors because my variables were not declared in scope, but I can't understand why.
// w4x.cpp
#include <iostream>
using namespace std;
#include "w4x.h"
#include "Molecule.h"
int main() {
int n = MAX_MOLECULES;
Molecule molecule[MAX_MOLECULES];
cout << "Molecular Information\n";
cout << "=====================" << endl;
for (int i = 0; i < MAX_MOLECULES; i++) {
if (!molecule[i].read()) {
n = i;
i = MAX_MOLECULES;
}
cout << endl;
}
cout << "Structure Name Mass\n";
cout << "==================================================" << endl;
for (int i = 0; i < n; i++)
molecule[i].display();
}
//Molecule.h
const int MAX_STRUCT = 10;
const int MAX_NAME = 20;
class Molecule {
char name[MAX_STRUCT];
char rate[MAX_NAME];
double weight;
public:
Molecule();
void read(const char*, const char*, double);
void display() const;
~Molecule();
};
//Molecule.cpp
#include <iostream>
#include <cstring>
using namespace std;
#include "Molecule.h"
Molecule::Molecule(){
name[0]= '\0';
rate[0]= '\0';
weight = 0;
}
void::read(const char* n, const char* r, double w) {
weight = w;
strncpy (name, n, MAX_STRUCT);
name[MAX_STRUCT]='\0';
strncpy (rate, r, MAX_NAME);
rate[MAX_NAME]='\0';
cout << "Enter structure : ";
cin.getline (n, MAX_CHARS);
cout << "Enter full name : ";
cin.getline (r, MAX_NAME);
cout << "Enter weight : ";
cin >> w;
}
void::display() const
{
int x;
for ( x=0; x<i; x++)
cout << n << " " << r << " " << w << endl;
}
My first question is, how can I pass char name[MAX_STRUCT]; char rate[MAX_NAME]; double weight; from Molecule.h to Molecule.cpp
The problem with your definitions is here:
void::read(const char* n, const char* r, double w)
and here
void::display() const
What :: says here, is that you are implementing a function within a class. So you need to specify which class and which function! What you are telling it now, is that you are implementing a function inside class void, which is nonexistent.
You should convert them to:
void Molecule::read(const char* n, const char* r, double w)
void Molecule::display() const
Your other question regarding passing class members:
The functions of a class have access to its variables, therefore, you don't need to concern yourself with that. Just use the variables.
Also, if you notice in your w4x.cpp, the function Molecule::read() is called without parameters, so your TAs ask you to implement it without parameters. Indeed, since you have access to Molecule::name, Molecule::rate and Molecule::weight directly, you should read data and write to those variables instead of asking for parameters. Therefore, your read function would look like this:
void Molecule::read()
{
// read into name, rate and weight
}
Furthermore, w4x.cpp expects read to report whether it has been successful or not. This means that you should do error checking in Molecule::read and return 0 if no errors or -1 (for example) in case of errors.