I get a compile error "cannot convert 'Chips' to 'GroceryItem' and I'm having trouble figuring out how to actually convert something to a virtual class object. Teacher provided a 'GroceryCart' class that adds GroceryItems to the cart in 'main' and prints the cart out.
class GroceryItem {
public:
virtual ~GroceryItem();
virtual float GetPrice() = 0;
virtual char* GetDescription() = 0;
virtual float GetWeight() = 0;
};
#include "GroceryItem.h"
class Chips : public GroceryItem {
public:
Chips();
~Chips();
float GetPrice();
char* GetDescription();
float GetWeight();
private:
float price;
char* itemName;
float weight;
};
#include "GroceryItem.h"
#include "Chips.h"
Chips::Chips() {
price = 0.75;
itemName = new char[5];
itemName = "Chips";
weight = 1.0;
}
Chips::~Chips() {
delete this;
}
float Chips::GetPrice() {
return price;
}
char* Chips::GetDescription() {
return itemName;
}
float Chips::GetWeight() {
return weight;
}
int main(int argc, const char * argv[])
{
GroceryCart c;
c.AddItemToCart(new Chips);
std::cout << c;
return 0;
}
void GroceryCart::AddItemToCart(GroceryItem *i)
{
items.push_back(i);
}
provide full error log, check that container parameterized with pointer to GroceryItem (<GroceryItem*>)
As someone pointed out
delete[] itemName; //destructor
but you also have to define non-trivial copy-constructor/operator=, so it's better to replace char* with std::string, also need defined destructor for base abstract class even it's pure virtual.
Related
Im a newbie in c++ and recently discovered classes;
I learned about constructors, overloading operators, the rule of three and right now i tried to learn inheritance.
I created 4 classes: 2 parents, 2 childs, but i occured some problems in class parent1
This is class parent1:
class parent1{
protected:
float slr;
int age;
char *name;
void set_new_name(char ch[10001]);
public:
parent1()
{
slr=0.0;
age=0;
name=NULL;
}
parent1(char ch[10001], float sl, int ag)
{
slr=sl;
age=ag;
set_new_name(ch);
}
parent1(const parent1 &p1)
{
char temp[10001];
strcpy(temp,p1.name);
if(name != NULL)
delete[] name;
set_new_name(temp);
slr=p1.slr;
age=p1.age;
}
parent1 &operator=(const parent1 &p1)
{
/// same lines as in copy constructor above
return *this;
}
char* get_name() const;
void print1();
~parent1()
{
delete[] name;
}
};
This is his child class, child1:
class child1 : public parent1{
protected:
int id;
void set_id(int j);
public:
child1(): parent1()
{
set_id(0);
}
child1(char ch[10001],float sl, int ag, int j): parent1(ch,sl,ag)
{
set_id(j);
}
child1(const child1 &p2): parent1(p2)
{
set_id(p2.get_id());
}
child1 &operator=(const child1 &p2)
{
set_id(p2.get_id());
parent1::operator=(p2);
}
int get_id() const;
void print2();
};
There is class parent 2:
class parent2{
protected:
char *name1;
char *name2;
void set_new_name1(char ch1[10001]);
void set_new_name2(char ch2[14]);
public:
parent2()
{
name1=NULL;
name2=NULL;
}
parent2(char ch1[10001], char ch2[14])
{
set_new_name1(ch1);
set_new_name2(ch2);
}
parent2(const parent2 &p3)
{
char temp2[10001];
strcpy(temp2,p3.name1);
if(name1 !=NULL)
delete[] name1;
set_new_name1(temp2);
/// .. . same lines as above, this time for name2 and p3.name2
}
parent2 &operator=(const parent2 &p3)
{
/// .. same lines as in copy constructor above
return *this;
}
char* get_name1() const;
char* get_name2() const;
void print3();
~parent2()
{
delete[] name1;
delete[] name2;
}
};
And there is his child, child 2:
class child2: public parent2{
protected:
char *job;
void set_new_job(char ch3[15]);
public:
child2(): parent2()
{
job=NULL;
}
child2(char ch1[10001], char ch2[10001],char ch3[11]): parent2(ch1,ch2)
{
set_new_job(ch3);
}
child2(const child2 &p4): parent2(p4)
{
char temp6[11];
strcpy(temp6, p4.job);
if(job != NULL)
delete[] job;
set_new_job(temp6);
}
child2 &operator=(const child2 &p4)
{
/// same lines as in copy constructor
parent2::operator=(p4);
}
char* get_job() const;
void print4();
~child2()
{
delete[] job;
}
};
As u can see up here, class parent1 have 3 types of parameters ( one float, one int and one char*).
Nonte: set_ functions works ok, get_functions just return class parametes (also works ok) , print functions just print classes parameters ( ex: cout << name1; also works fine)
The problem is that this code refuse to work when i create the objects in main.
First i thought it is operator= being overloaded to many times, bit it turned out to be the float parameter from parent1
There is the main:
char ch[10001]="my name", ch1[10001]="my name 1", ch2[14]="my name 2", ch3[11]="some code";
int ag=10;
float sl=10.1;
parent1 o1;
o1=parent1(ch,sl,ag);
o1.print1();
parent1 o2(o1);
o2.print1();
child1 o3;
o3=child1(ch,sl,ag,3);
o3.print2();
child1 o4;
o4=child1(ch,sl,ag,6);
o4.print2();
o4=o3;
o4.print2();
parent2 o5;
o5=parent2(ch1,ch2);
o5.print3();
child2 o6(ch1,ch2,ch3);
o6.print4();
The only things that seems to make it run are:
deleting the float parameter from parent1;
deleting the last class ; (i really don't know why the last class affect the program)
creating the last object like this : child2 o6(ch1,ch2,ch3); , which is frustrating because it should work like the others;
I know the code i sheared is very long, but Please , Help me to understand what i need to do to solve this stupid bug !
I see at least 3 issues in the code that will lead to a crash/undefined behavior.
First:
parent1(const parent1 &p1)
{
char temp[10001];
strcpy(temp,p1.name);
if(name != NULL) // name isn't initialized yet,
delete[] name; // these 2 lines shouldn't be here
set_new_name(temp);
slr=p1.slr;
age=p1.age;
}
Second: (these ones are reported by the compiler when warnings are enabled)
child1 &operator=(const child1 &p2)
{
set_id(p2.get_id());
parent1::operator=(p2);
return *this; // this line is missing
}
Third:
child2 &operator=(const child2 &p4)
{
char temp7[11];
strcpy(temp7, p4.job);
if(job != NULL)
delete[] job;
set_new_job(temp7);
parent2::operator=(p4);
return *this; // this line is missing
}
The return statement is not "inherited". Each function that's supposed to return something must do so.
With these changes the code runs:
my name
my name
3
6
3
my name 1
my name 2
some code
(Live demo)
Some additional improvement notes:
An array like char ch[10001] can't really be a function argument in C++. When it's used as an argument it silently decays to char *. So you might as well replace all char ch[10001] with const char* ch (and better yet, std::string), to avoid confusion.
Also, there's no point in allocating a temp array. You can just directly do set_new_name(p1.name):
parent1(const parent1 &p1)
{
set_new_name(p1.name);
slr=p1.slr;
age=p1.age;
}
It would be prudent to invest some time in getting familiar with a Debugger. It's all but impossible to make a working application without debugging it. And enable compiler warnings. With GCC use -Wall -Wextra, with MSVC - /W4.
Here's an example of the code using std::string. Thanks to std::string we can follow the rule of 0:
class parent1 {
protected:
float slr = 0;
int age = 0;
string name;
void set_new_name(string const &ch) { name = ch; }
public:
parent1() {}
parent1(string const &name, float slr, int age)
: slr(slr), age(age), name(name) {}
string const &get_name() const { return name; }
void print1();
};
void parent1::print1() { cout << get_name() << '\n'; }
class child1 : public parent1 {
protected:
int id = 0;
void set_id(int j) { id = j; }
public:
child1() : parent1() {}
child1(string const &name, float sl, int ag, int j)
: parent1(name, sl, ag), id(j) {}
int get_id() const { return id; }
void print2();
};
void child1::print2() { cout << get_id() << '\n'; }
class parent2 {
protected:
string name1;
string name2;
void set_new_name1(string const &ch) { name1 = ch; }
void set_new_name2(string const &ch) { name2 = ch; }
public:
parent2() {}
parent2(string const &name1, string const &name2)
: name1(name1), name2(name2) {}
string const &get_name1() const { return name1; }
string const &get_name2() const { return name2; }
void print3();
};
void parent2::print3() {
cout << get_name1() << '\n';
cout << get_name2() << '\n';
}
class child2 : public parent2 {
protected:
string job;
void set_new_job(string const &ch) { job = ch; }
public:
child2() : parent2() {}
child2(string const &name1, string const &name2, string const &job)
: parent2(name1, name2), job(job) {}
string const &get_job() const { return job; }
void print4();
};
void child2::print4() { cout << get_job() << '\n'; }
And this works equally well.
I have these classes:
class PC
{
public:
PC(string in_operatingSystem,int in_ramSlots,int in_pcieSlots,int in_totalRamSlots, int in_gbPerRam, int in_cpu, int in_ssd, int in_cost);
virtual void Print() = 0;
virtual void Upgrade() = 0;
protected:
string operatingSystem;
int ramSlots,pcieSlots,totalRamSlots,gbPerRam;
int cpu,ssd;
int cost;
};
class HomePC: public PC
{
public:
HomePC(string in_operatingSystem,int in_ramSlots,int in_pcieSlots,int in_totalRamSlots, int in_gbPerRam, int in_cpu, int in_ssd, int in_cost, string in_model);
void Print();
void Upgrade(){};
private:
string model;
};
and I'm saving the content into the vectors like this:
PCList.push_back(new HomePC("MacOS",2,0,1,4,2,256,800,Model));
I'm trying to find a way to find a specific Model(for example UserPC) in vector and erase this PC from my list.
You can add a getter for model
class HomePC: public PC
{
public:
HomePC(string in_operatingSystem,int in_ramSlots,int in_pcieSlots,int in_totalRamSlots, int in_gbPerRam, int in_cpu, int in_ssd, int in_cost, string in_model);
void Print();
void Upgrade(){};
std::string getModel() const { return model; }
private:
string model;
};
and dynamic cast each element:
for (auto pcIt = PCList.cbegin(); pc != PCList.cend(); ++pc) {
const auto * const homePc = dynamic_cast<HomePC *>(*pcIt);
if (homePc && homePc->getModel() == "UserPC") {
PCList.erase(pcIt);
break;
}
}
You have to add a virtual destructor to PC otherwise you can't dynamic cast.
Otherwise erasing, you can try different ways
std::vector<std::unique_ptr<HomePC>> pileTemp;
std::vector<std::unique_ptr<HomePC>> pileTarget;
std::unique_ptr<HomePC> p1(new HomePC("Windows",2,0,1,4,2,256,800,"UserPC"));
pileTemp.push_back(std::move(p1));
std::unique_ptr<HomePC> p2(new HomePC("MacOs",2,0,1,4,2,256,800,"PCUser"));
pileTemp.push_back(std::move(p2));
std::for_each(pileTemp.begin(), pileTemp.end(), [&](std::unique_ptr<HomePC>& p)->void{ if(p->getmodel() != "UserPC" ) {
pileTarget.push_back(std::move(p));
}
});
Then, you can clear the temporary container.
I cannot understand why this does not compile:
#include<iostream>
#include<string>
using namespace std;
class Product {
public:
virtual void print() = 0;
virtual void slog() = 0;
virtual void loft() = 0;
};
class Bike: public Product {
private:
string s;
public:
Bike(string x){
s = x;
}
void print() {
std::cout << "Bike";
}
int slog() {
return 4;
}
string loft() {
return s;
}
};
int main() {
string s("Hello");
Product *p = new Bike(s);
p->print(); //works fine
cout << p->slog();//works fine
cout << p->loft(); //error
return 0;
}
The above code results in error. Why can't I override string class.
I want to call loft() using the pointer p.
Is there any way to achieve this using pointer object to abstract class Product
Firstly, you need to include string #include <string>.
There's no problem with loft method, you have a problem with print method. Child class has a return type of string and base class has a return type of void, thus you're not really overriding the function. Compiler sees the declaration of void print() in base class and you can't do a cout on that.
Here's your code with few fixes and comments on them, it should work fine.
#include <iostream>
#include <string>
using namespace std;
class Product {
public:
virtual void print() = 0;
virtual int slog() = 0;
virtual string loft() = 0;
//added virtual destructor so you can use pointer to base class for child classes correctly
virtual ~Product() {};
};
class Bike: public Product {
string s;
public:
Bike(string x) {
s = x;
}
void print() {
cout << "Bike";
}
int slog() {
return 4;
}
string loft() {
return s;
}
};
int main() {
string s("Hello");
Product *p = new Bike(s);
p->print();
cout << p->slog();
cout << p->loft();
return 0;
}
Also, please try to format your code better next time, it makes it easier to read
Here I've made a derived class called Essay, from the base class GradedActivity. I've made an object of the Essay class in main called object. When I wrote object.setGrammar(grammarPts) in main(), I'd hoped to feed what the score is to be held in the variable grammar in the setGrammar() function. What am I doing wrong? Thanks!
I get one error:
99 8 F:\lab6part3.cpp [Error] request for member 'setGrammar' in 'object', which is of non-class type 'Essay(float, float, float, float)'
#include <iostream>
using namespace std;
//class gradedactivity (page 900)
class GradedActivity
{
protected:
double score;
public:
//default constructor
GradedActivity()
{
score = 0.0;
}
//parameterized constructor
GradedActivity(double s)
{
score = s;
}
setScore(double s)
{
score = s;
}
double getScore() const
{
return score;
}
char getLetterGrade() const;
};
class Essay : public GradedActivity
{
private:
float grammar;
float spelling;
float length;
float content;
public:
Essay(float g, float s, float l, float c)
{
setGrammar(g);
setSpelling(s);
setLength(l);
setContent(c);
}
void setGrammar(float);
float getGrammar();
void setSpelling(float);
float getSpelling();
void setLength(float);
float getLength();
void setContent(float);
float getContent();
};
void Essay::setGrammar(float g)
{
grammar = g;
}
float Essay::getGrammar() {return grammar;}
void Essay::setSpelling(float s)
{
spelling = s;
}
float Essay::getSpelling() {return spelling;}
void Essay::setLength(float l)
{
length = l;
}
float Essay::getLength() {return length;}
void Essay::setContent(float c)
{
content = c;
}
float Essay::getContent() {return content;}
int main()
{
float grammarPts;
cout << "How many points, out of 30, did the student get for grammar?";
cin >> grammarPts;
Essay object;
object.setGrammar(grammarPts);
return 0;
}
This could just be because you never defined a default constructor for Essay.
Anyway, I defined a default constructor and your code runs fine so that might be the issue. https://ideone.com/yNxV8N
I have looked all around and can't find the answer to my question anywhere. I am trying to use a copy constructor of a derived class from a pointer array of base classes. The only thing I have learned is I should probably use dynamic_cast but cant get that working.
This is the important parts of my code so far (original is way to big since I have 16 different files but this should be enough).
EDIT: The error I receive doing it this way is |26|error: cannot dynamic_cast '& properties[0]' (of type 'class Property**') to type 'class Commercial*' (source is not a pointer to class)|
#include "rentals.h"
#include "commercial.h"
#include "sales.h"
#include "comSales.h"
#include "resSales.h"
#include "resRentals.h"
#include "comRentals.h"
const int MAX_PROPERTIES = 5;
int main(void) {
int i;
Property *properties[MAX_PROPERTIES];
properties[0] = new Commercial("Notting Hill McDonalds", "4 Gardiner Road",
"Notting Hill", 5000, "Li3000");
properties[1] = new ResRentals("Janet Dalgleish", "30 Firhill Court",
"Mary Hill", 4000, 500.00, 300.00, 4);
properties[2] = new Commercial(dynamic_cast<Commercial*>(properties[0])); // <-- the copy constructor I can not get to work.
delete[] properties;
return 0;
}
commercial.cpp file
#include "property_a.h"
#include "commercial.h"
Commercial::Commercial() : Property() {
owner = "NULL";
address = "NULL";
suburb = "NULL";
postcode = 0;
license = "NULL";
}
Commercial::Commercial(string theOwner, string theAddress,
string theSuburb, int thepostCode,
string theLicense): Property(theOwner, theAddress,
theSuburb, thepostCode), license(theLicense) {}
Commercial::~Commercial() {}
Commercial::Commercial(const Commercial& orig) : Property(orig),
license(orig.getLicense()) {}
void Commercial::print() {
cout << getOwner() << endl;
cout << getAddress() << endl;
cout << getSuburb() << endl;
cout << getPostcode() << endl;
cout << getLicense() << endl;
}
commercial.h file
#ifndef __COMMERCIAL_H__
#define __COMMERCIAL_H__
#include "property_a.h"
class Commercial : public virtual Property
{
protected:
string license;
public:
Commercial();
Commercial(string theOwner, string theAddress, string theSuburb,
int thepostCode, string theLicense);
~Commercial() ;
Commercial(const Commercial& orig);
void input() ; // Data input for a Shop object
void print() ; // Data output for a Shop object
string getLicense() const {return license;}; //Note the use of const
void setLicense(string theLicense) {license = theLicense;};
};
property_a.cpp file
#include "property_a.h"
Property::Property(){
owner = "NULL";
address = "NULL";
suburb = "NULL";
postcode = 0;
}
Property::Property(string theOwner, string theAddress,
string theSuburb, int thepostCode):
owner(theOwner), address(theAddress),
suburb(theSuburb), postcode(thepostCode){}
Property::~Property() {}
Property::Property(const Property& orig) :
owner(orig.getOwner()), address(orig.getAddress()),
suburb(orig.getSuburb()), postcode(getPostcode()) {}
property_a.h file
#ifndef __PROPERTY_A_H__
#define __PROPERTY_A_H__
/*TODO REQUIRED HEADER FILES AND NAMESPACES*/
#include <string>
#include "utility1.h"
class Property
{
protected:
string owner;
string address;
string suburb;
int postcode;
public:
Property();
Property(string theOwner, string theAddress, string theSuburb, int thepostCode);
virtual ~Property();
Property(const Property& orig);
virtual void input() ; // Data input for a Property object
virtual void print() ; // Data output for a Property object
string getOwner() const {return owner;}; //Note the use of const
string getAddress() const {return address;};
string getSuburb() const {return suburb;};
int getPostcode() const {return postcode;};
void setOwner(string newOwner) {owner = newOwner;};
void setAddress(string newAddress) {address = newAddress;};
void setSuburb( string newSuburb) {suburb = newSuburb;};
void setPostcode(int newPostcode) {postcode = newPostcode;};
};
#endif
I hope this is enough details
properties[2] = new Commercial(dynamic_cast(properties[0])); // <-- the copy constructor I can not get to work.
This is casting properties[0] to Commercial*. But this isn't the signature of your copy constructor. Therefore, you need new Commercial(*dynamic_cast<Commercial*>(properties[0]));.
In this example you could use static_cast<Commercial&>(*properties[0]) since you know properties[0] is a Commercial type.
However, in general if you're using dynamic_cast it probably means you're not sure what the derived type is and you would need to check for NULL (i.e., the cast failed) before dereferencing.
Alternative
You could consider a polymorphic API to take care of this for you.
class Base
{
public:
virtual ~Base() = default;
Base* clone() const = 0;
};
class D1 : public Base
{
public:
virtual ~D1() override = default;
D1* clone() const { return new D1(*this); }
};
class D2 : public Base
{
public:
virtual ~D2() override = default;
D2* clone() const { return new D2(*this); }
};
int main()
{
std::unique_ptr<Base> b1(new D2());
std::unique_ptr<Base> b2(b1->clone());
return 0;
}
It would be nice to see the errors but it looks like you aren't calling the copy constructor at all:
new Commercial(dynamic_cast<Commercial*>(properties[0]));
is like calling
Commercial(Commercial * other);
so you need
new Commercial(*dynamic_cast<Commercial*>(properties[0]));