C++ can you downcast class pointer conditionally? - c++

I have a base class (robot) and depending on the arguments passed to the program I want to downcast the robot pointer to a specific derived class. the robot class has virtual functions which are defined in each of the derived classes.
So far I can create a pointer of the base class, and within a conditional statement, create a derived class which the base is then dynamically cast to. Within the conditional the pointer works as intended but after leaving the conditional statement the derived class is out of scope and the functions go back to virtual. Is there a way I can keep the pointer to the derived class?
class vehicles{
public:
virtual void print_state(int state_ind, ofstream& file){}
};
class hovercraft : public vehicles{
public:
hovercraft(
int L_in, int W_in,
double start_x, double start_y,
double goal_x, double goal_y)
{
L = L_in;
W = W_in;
start_state.x = start_x;
start_state.y = start_y;
goal_state.x = goal_x;
goal_state.y = goal_y;
Tree.push_back(start_state);
}
void print_state(int state_ind, ofstream& file){
state s = Tree[state_ind];
file<<s.phi<<","<<
s.u<<","<<
s.v<<","<<
s.r<<","<<
s.x<<","<<
s.y<<"\n";
}
private:
struct state{
double g=0;
double u=0;
double v=0;
double r=0;
double x=0;
double y=0;
double phi=0;
int p=0;
};
int L,W;
state start_state, goal_state, state_sample;
vector<state> Tree;
};
int main(int argc, char* argv[])
{
ifstream infile;
string vehicle_name;
vehicles* vehicle;
int start, goal;
for(int i=0; i < argc; i++){
if (string(argv[i])=="-m"){
infile.open (argv[i+1]);
} else if (string(argv[i])=="-v"){
vehicle_name = string(argv[i+1]);
}
}
ofstream file_out;
file_out.open ("state.csv");
if(vehicle_name == "hovercraft"){
int L, W;
double start_x, start_y, goal_x, goal_y;
infile >> L;
infile >> W;
infile >> start_x;
infile >> start_y;
infile >> goal_x;
infile >> goal_y;
hovercraft my_vehicle(L,W, start_x, start_y, goal_x, goal_y);
hovercraft* vehicle = dynamic_cast<hovercraft*>(&my_vehicle);
} else {
cout<<"Invalid Vehicle: "<<vehicle_name<<"\n Exiting...\n";
return 0;
}
vehicle->print_state(0);
}
This is simplified from the actual code but I think it captures the issue. The result I want is for print to work the same inside the if statement and after it but after it will always print "no vehicle".

You're overloading the variable rptr inside the scope of your if-statements, which hides the one declared at the top of main. Your final rptr->print() is therefore undefined behavior, because you're calling a virtual function on an uninitialized pointer.
Simply remove the overloading as follows:
robot *rptr = nullptr;
if (*argv[1] == 'h') // <-- also fixed this (yours was broken)
{
rptr = new hovercraft();
rptr->print();
}
else if (*argv[1] == 'q') // <-- also fixed this (yours was broken)
{
rptr = new quadrotor();
rptr->print();
}
else
{
std::cout << "Invalid vehicle input" << std::endl;
}
if (rptr)
{
rptr->print();
}
You might also want to consider using std::shared_ptr or std::unique_ptr (along with std::make_shared or std::make_unique) to correctly manage the lifetime of dynamic memory.

Related

Types myObj and myObj* are not compatible

class boundaryPt{
public:
friend class KCurvature;
int x;
int y;
boundaryPt(int x, int y){
this->x = x;
this->y = y;
}
boundaryPt(){}
};
class KCurvature{
public:
boundaryPt* boundaryPtAry;
int numPts;
ifstream input;
KCurvature(char* inFile){
input.open(inFile);
input >> numPts;
boundaryPtAry = new boundaryPt[numPts];
}
void loadData(char* inFile){
input.open(inFile);
int x;
int y;
while(!input.eof()){
input >> x;
input >> y;
boundaryPtAry[index++] = new boundaryPt(x,y);
}
};
My issue is with:
boundaryPtAry[index++] = new boundaryPt(x,y);
I'm trying to store my boundaryPt objects in my array of type boundaryPt, but since I declared that array as boundaryPt* it wont let me a store a boundaryPt.
Is this a simple issue of deferencing a pointer? I'm rusty with C++.
SOLVED! I realize now that when creating an array of objects, you are not just creating an array, but the objects themselves as well. So there was no need to create a new object and try and put it in the array(or in my case have the array index point to it).
while(!input.eof()){
input >> boundaryPtAry[index].x;
input >> boundaryPtAry[index].y;
index++;
}

C++ "No matching constructor for initializing Employee"

I am new to C++ and practicing using vector as an object. However, I got an error "No matching constructor for initializing Employee" when I tried running the following program.
Please tell me how I could modify my program!
Also, when I write
staff[0] = Employee{"Harry Potter" 55000};
does this mean that I am storing string and double data in one of 10 open boxes in vector object of type Employee?
I apologize for such a basic question.
Thank you so much in advance!!
#include<iostream>
#include<string>
#include<vector>
using namespace std;
class Employee
{
public:
Employee(string, double);
double get_salaries();
string get_name();
void set_salaries(double);
private:
string name;
double salaries;
};
Employee::Employee(string n, double s)
{
name = n;
salaries = s;
}
double Employee::get_salaries()
{
return salaries;
}
string Employee::get_name()
{
return name;
}
void Employee::set_salaries(double s)
{
salaries = s;
}
int main()
{
// using vector as an object
int i;
vector<Employee> staff(10);
staff[0] = Employee{"Harry Potter", 55000};
if (staff[i].get_salaries() < 100000)
cout << staff[i].get_salaries();
return 0;
}
Your Employee class does not have a default, parameterless, constructor.
When you create the staff vector, it will create 10 Employee objects, thus invoking the default constructor.
To support this,
vector<Employee> staff(10);
you have to provide default constructor in your class.
Your main method
int main()
{
// using vector as an object
int i; // [i] not initialized anywhere.
vector<Employee> staff(10); // Incorrect way of declaring a vector
staff[0] = Employee{"Harry Potter", 55000}; // Incorrect way of creating a instance of class
if (staff[i].get_salaries() < 100000)
cout << staff[i].get_salaries();
return 0;
}
Change your main method like this
int main()
{
vector<Employee> staff;
staff.push_back(Employee("Harry Potter", 55000));
if (staff[0].get_salaries() < 100000)
cout << staff[0].get_salaries();
return 0;
}

Casting objects in vector in c++

I know this question has already been asked, but none of the answers that I have as of yet found seem to suffice. I am creating a vector of pointers to a base class and adding all sorts of derived classes to it. Now, the base class has a virtual function that is overridden in all of the derived classes and that is unique to each of them. So, when I go through the vector and retrieve those objects and call the function on that object, I need it to call the right one, but all it will do is call the base class version. I am even trying to cast the individual elements back to their original class when I retrieve them from the vector but they refuse to be cast! e.g.
vector<base*> myBase;
DerivedClass *myDerived = static_cast<DerivedClass> myBase[i];
This doesn't work, despite the fact that everything I've read suggests that it should. My debugger says that despite all of this, myDerived is still of type base and it's version of my virtual function is being called.
Any ideas?
class BankAccount {
public:
BankAccount(string namein, string typein){
name = namein;
type = typein;
balance = 0;
}
virtual string getType();
virtual void printTransactions() = 0;
virtual int withdraw(double amt){
return getBalance() -amt;
}
};
class SavingsAccount: public BankAccount {
public:
SavingsAccount(string namein, string typein);
void addTransaction(string transType, string name);
virtual int withdraw(double amt);
void printTransactions();
virtual string getType();
private:
};
SavingsAccount::SavingsAccount(string namein, string typein): BankAccount(namein, typein) {
}
int SavingsAccount::withdraw(double amt){
double aBal = getBalance() - amt;
if (aBal > 0){
setBalance(aBal);
}
return getBalance() - amt;
}
class CheckingAccount: public SavingsAccount {
public:
CheckingAccount(string nameIn, string typein): SavingsAccount(nameIn, typein){
}
virtual int withdraw(double amt);
void printTransactions();
string getType(){
return "Checking";
}
};
int CheckingAccount::withdraw(double amtIn){
double newBal = getBalance() - amtIn;
if (newBal < 500.00 && newBal > 2.49) {
setBalance(newBal - 2.50);
}
return newBal;
}
int main(int argc, const char * argv[])
{
vector<BankAccount*> myAccts;
SavingsAccount *mySav;
CD *myCD;
CheckingAccount *myCheck;
switch (option) {
case 1: {
string name;
string type;
cout << "Enter name: ";
cin >> name;
getline(cin, dump);
cout << "Enter account type: ";
cin >> type;
getline(cin, dump);
if (type.compare("Checking") == 0) {
CheckingAccount myCheck1 = CheckingAccount(name, type);
myAccts.push_back(&myCheck1);
}
case 3:{
for (int x = 0; x < myAccts.size(); x++) {
if (myAccts[x]->getName() == name && myAccts[x]->getType() == type) {
if (type == "Savings") {
mySav = static_cast<SavingsAccount*>(myAccts[x]);
double y = mySav->withdraw(amt);
if (y < 0){
cout << "Insufficient funds!";
}
}
if (type == "Checking") {
myCheck = myAccts[x]->GetDerived();
double y = myCheck->withdraw(amt);
if (y < 0){
cout << "Insufficient funds!";
}
if (y < 497.5) {
cout << "Withdrawal fee: $ 2.50" << endl;
}
}
}
Checking Account is a child of Savings Account. Sorry.
Your concept is correct and shouldn't require any casting. The whole point of virtual functions is that if you're holding a base class pointer or reference and call a virtual function, the most derived version of this function will be called at runtime.
The error I see is this:
if (type.compare("Checking") == 0) {
CheckingAccount myCheck1 = CheckingAccount(name, type);
myAccts.push_back(&myCheck1);
You are creating a checking account on the stack, then taking it's address and pushing that address into the vector. At the end of the if block myCheck1 will go out of scope and be destroyed. Your vector will have an address to a location in the stack and you will have Undefined Behavior.
Instead do:
if (type.compare("Checking") == 0) {
myAccts.push_back(new CheckingAccount(name, type));
And similar for the other types. Get rid of all of those casts. In this version you will have to delete all of the items in the vector at the end. If you use a std::vector<std::unique_ptr<BankAccount>> then the unique_ptr will take care of cleaning up your allocated objects.
You need to use new to create your accounts... you have:
if (...)
{
CheckingAccount myCheck1 = CheckingAccount(name, type);
myAccts.push_back(&myCheck1);
}
...myCheck1 gets destroyed when leaving that if scope, leaving myAccts with a pointer to an effectively random location on the stack that has undefined behaviour if accessed. Change to:
if (type == "Checking")
myAccts.push_back(new CheckingAccount(name, type));
You will then need to have matching deletes for the vector elements. Googling "C++ new delete tutorial" would be a good idea. The next stage is to learn how to use smart pointers, for example - std::shared_pointer - which remove the burden of remembering to delete.
"Case 3" can be corrected/simplified to:
for (int x = 0; x < myAccts.size(); x++)
if (myAccts[x]->getName() == name && myAccts[x]->getType() == type) {
double y = myAccts[x]->withdraw(amt);
if (y < 0)
cout << "Insufficient funds!";
if (type == "Checking" && y < 497.5)
cout << "Withdrawal fee: $ 2.50" << endl;
}
Notice in particular the double y = myAccts[x]->withdraw(amt); - the virtual function makes sure the right version is called without you having to do anything type-specific in the calling code.
Have you tried something like this?
class base
{
public:
inline DerivedClass *GetDerived() {return (DerivedClass*)this;}
...
};
DerivedClass *myDerived = myBase[i]->GetDerived();

Aggregation using C++

I am trying to make one class work with another class. It is supposed to decrement the member of the other class.
my first class is
class Bike
{
private:
int miles;
Speedometer speedom;
static int fuelCount;
public:
Bike();
Bike(int, Speedometer*); //Problem occurs here
~Bike();
int getMiles();
int getFuelCount();
void incrementMiles();
};
int Bike::fuelCount = 0;
Bike::Bike()
{
miles = 0;
fuelCount++;
}
Bike::Bike(int m, Speedometer * spm) //This is where I am having problems
{
miles = m;
speedom = &spm;
}
Bike::~Bike()
{
cout << "The Bike's destructor is running." << endl;
fuelCount--;
}
int Bike::getMiles()
{
return miles;
}
int Bike::getFuelCount()
{
return fuelCount;
}
void Bike::incrementMiles()
{
miles++;
if (miles == 999999)
miles = 0;
}
The other class which is supposed to be included in the first is:
Class Speedometer
{
private:
int fuel;
public:
Speedometer();
Speedometer(int);
~Speedometer();
int getFuel();
void incrementFuel();
void decrementFuel();
};
Speedometer::Speedometer()
{
fuel = 0;
}
Speedometer::Speedometer(int f)
{
fuel = f;
}
int Speedometer::getFuel()
{
return fuel;
}
void Speedometer::incrementFuel()
{
if (fuel <= 15)
fuel++;
}
void Speedometer::decrementFuel()
{
if (fuel > 0)
fuel--;
}
They are supposed to work together. Bike is to be able to work with speedometer object. It should decrease the speedometers current amount of fuel by one gallon for every 24 miles traveled.
This is supposed to be a aggregate relationship not composition.
Please help me just understand how to make that relationship and how its supposed to be called.
Thank you in advance.
here is my main function
btw - i have all the right #includes i just have not listed them here
int main(int argc, char *argv[])
{
Speedometer a(999970, spd);
for(int count = 0; count <=24; count++)
a.decrementMiles();
while (a.getFuel() > 0)
{
a.incrementMiles();
cout<< "Miles:" << a.getMiles() << endl;
cout<< "Fuel:" << a.getFuel() << endl;
}
return 0;
}
You have a large number of issues here.
First of all, in your main(), you construct your Speedometer object with a constructor you have not implemented. The only constructors you have defined are the default constructor and Speedometer(int). You then call Speedometer(int, ???), the ??? being spd because you do not declare spd anywhere in the code you have provided, so we have no idea what it is.
It's really impossible to say what's wrong with your code in its current state.
As written, you've made a composition; Speedometer is part of Bike since it is a field. To make it an aggregation, make Bike hold a pointer to Speedometer. Note that as a consequence, you'll probably need Bike to create or obtain an initial Speedometer (could be NULL to begin with, or pass one in the constructor), and you might want to add accessor methods to Bike in order to add/remove/change the Speedometer.
[edit] Bike might also need to know how to dispose of the Speedometer properly in order to avoid leaking it.
[edit 2] Also as #cjm571 pointed out, your main function is creating and operating directly upon a "disembodied" Speedometer. Shouldn't it be on a Bike? :)
#include <iostream>
using namespace std;
class Bike
{
private:
int miles;
static int fuelCount;
// Speedometer speedom;
public:
Bike();
Bike(int); // Speedometer *); check comment on line 82
~Bike();
int getMiles();
int getFuelCount();
void incrementMiles();
};
int Bike::fuelCount = 0;
Bike::Bike()
{
miles = 0;
fuelCount++;
}
Bike::Bike(int m)//Speedometer (*spm) I don't see the purpose of this in the current state of the program, I may not be seing the whole picture
{
miles = m;
/* speedom = spm; remember, there must be a parent and a child class, at the current state you'r trying
to call a child from parent, the child class has not been defined, so i switched them and now Bike is a chiled. */
}
Bike::~Bike()
{
cout << "The Bike's destructor is running." << endl;
fuelCount--;
}
int Bike::getMiles()
{
return miles;
}
int Bike::getFuelCount()
{
return fuelCount;
}
void Bike::incrementMiles()
{
miles++;
if (miles == 999)
miles = 0;
}
class Speedometer
{
private:
int fuel;
public:
Speedometer();
Speedometer(int f);
int getFuel();
Bike theBike; // This is what you needed in order to make incrementMiles to work.
void incrementFuel();
void decrementFuel();
};
Speedometer::Speedometer()
{
fuel = 0;
}
Speedometer::Speedometer(int f)
{
fuel = f;
}
int Speedometer::getFuel()
{
return fuel;
}
void Speedometer::incrementFuel()
{
if (fuel <= 15)
fuel++;
}
void Speedometer::decrementFuel()
{
if (fuel > 0)
fuel--;
}
int main(int argc, char *argv[])
{
Speedometer a(999); //You never declared this, did you mean spm???
for(int count = 0; count <=24; count++)
a.theBike.incrementMiles();
while (a.getFuel() > 0)
{
a.theBike.incrementMiles();
cout<< "Miles:" << a.theBike.getMiles() << endl;
cout<< "Fuel:" << a.getFuel() << endl;
}
cin.get();
return 0;
} //There is no break declared (that i can see at least) so the program runs an infinite loop
// Don't want to add too many things to it, I don't know what your plan is.
// Hoping to have made it clearer.

Constructors and array of object in C++

I'm trying to create an application in C++. In the application I have the default constructor and another constructor with 3 arguments.
The user is providing from the keyboard an integer that it will be used to create an array of objects using the non default constructor.
Unfortunately I haven't been able to finish it till now, since I'm having issues with the creation of the array of objects that they will use the non default constructor.
Any suggestions or help?
#include<iostream>
#include<cstring>
#include<cstdlib>
#include <sstream>
using namespace std;
class Station{
public:
Station();
Station(int c, char *ad, float a[]);
~Station();
void setAddress(char * addr){
char* a;
a = (char *)(malloc(sizeof(addr+1)));
strcpy(a,addr);
this->address = a;
}
void setCode(int c){
code=c;
}
char getAddress(){
return *address;
}
int getCode(){
return code;
}
float getTotalAmount(){
float totalAmount=0;
for(int i=0;i<4;i++){
totalAmount+=amount[i];
}
return totalAmount;
}
void print(){
cout<<"Code:"<<code<<endl;
cout<<"Address:"<<address<<endl;
cout<<"Total Amount:"<<getTotalAmount()<<endl;
cout<<endl;
}
private:
int code;
char *address;
float amount[4];
};
Station::Station(){
code= 1;
setAddress("NO ADDRESS GIVEN");
amount[0]= 0.0;
amount[1]= 0.0;
amount[2]= 0.0;
amount[3]= 0.0;
}
Station::Station(int c, char *ad, float a[]){
if( (c>=1&& c<=10 ) ){
code=c;
address=ad;
for(int i=0;i<4;i++){
amount[i]=a[i];
}
}else{
code= 1;
setAddress("NO ADDRESS GIVEN");
amount[0]= 0.0;
amount[1]= 0.0;
amount[2]= 0.0;
amount[3]= 0.0;
}
}
Station::~Station(){
}
int main(){
int size,code;
char *addrr;
addrr = (char *)(malloc(sizeof(addrr+1)));
float mes[4];
do{
cout<<"size of array:";
cin>>size;
}while(size<=0 || size>=11);
// Station *stations= new Station[size];
// Station** stations = new Station*[size];
Station stations[size];
for(int i=0;i<size;i++){
cout<<"code:";
cin>>code;
cout<<"address:";
cin>>addrr;
double amo=0;
for(int k=0;k<4;k++){
cout<<"values"<<k+1<<":";
cin>>mes[k];
}
}
/*
for(int q=0;q<size;q++){
stations[q].print();
}
*/
return 0;
}
the values that I'll take from cin I want to assign them to the objects of the array!
You can either create the array default-initialized and then fill the array with the wanted object:
foo arr[10];
std::fill(arr, arr+10, foo(some, params));
Alternatively you could use std::vector and do just:
std::vector<foo> arr(10, foo(some, params));
In C++0x, you can use braced-init-list in new expression, which means you can do this:
#include <iostream>
class A
{
public:
A(int i, int j){std::cout<<i<<" "<<j<<'\n';}
};
int main(int argc, char ** argv)
{
int *n = new int[3]{1,2,3};
A *a = new A[3]{{1,2},{3,4},{5,6}};
delete[] a;
delete[] n;
return 0;
}
Compiled under g++ 4.5.2, using g++ -Wall -std=c++0x -pedantic
Since you say you can't use std::string, this is going to be much more difficult. The line addrr = (char *)(malloc(sizeof(addrr+1))); is not doing what you think it is. Instead of using malloc to allocate on the heap and since there is no free (which will lead to a memory leak), it will be much easier if we allocate on the stack with a predetermined buffer size: char addrr[BUFFER_LENGTH]. With BUFFER_LENGTH defined before Station's declaration as const int BUFFER_LENGTH = 20; or some other appropriate length.
To use the non-default constructor, adding stations[i] = Station(c, addrr, mes); at the end of the for loop will do the trick.
for(int i=0;i<size;i++){
cout<<"code:";
cin>>code;
cout<<"address:";
cin>>addrr; // do not read in strings longer than 20 characters or increase BUFFER_LENGTH’s size
double amo=0;
for(int k=0;k<4;k++){
cout<<"values"<<k+1<<":";
cin>>mes[k];
}
stations[i] = Station(c, addrr, mes);
}
But, this is not going to work properly since the constructor is copying the addrr pointer, not the data. I would recommend also changing the data member char *address to char address[BUFFER_LENGTH]. Then, in the constructor you can replace the line address=ad; with strcpy(address, ad);.
Note: setAddress and getAddress will now need to be updated.
Another line that is troubling is Station stations[size];. This is non-standard since size is not a known at compile time. Either use Station *stations= new Station[size]; and remember to delete or if you can use a std::vector, use std::vector<Station> stations(size);
If you do go the std::vector route, using push_back will work nicely:
std::vector<Station> stations;
for(int i=0;i<size;i++){
cout<<"code:";
cin>>code;
cout<<"address:";
cin>>addrr;
double amo=0;
for(int k=0;k<4;k++){
cout<<"values"<<k+1<<":";
cin>>mes[k];
}
stations.push_back( Station(c, addrr, mes) );
}