This code works appropriately if I don't use and then delete a pointer for the base class Output. The destructor for Output is called and seems to work appropriately. Am I missing something here?
// multiple inheritance
// Testing overload of muliple inheritance of pure virtual functions.
#include <iostream>
#include <string>
using namespace std;
class Polygon {
protected:
int width, height;
public:
Polygon (int a, int b) : width(a), height(b) {}
~Polygon() = default;
virtual int area() = 0;
};
class Output {
private:
string* myString;
public:
Output() {
myString = nullptr;
}
Output(const string& s) {
myString = new string(s);
}
// This seems to work, but ther core dump happens right afterwards.
~Output() {
cout << "delete called with: " << myString << '\n';
if (myString != nullptr)
delete myString;
}
virtual int area() = 0;
void print () {
cout << *myString << this->area() << '\n';
}
};
class Rectangle: public Polygon, public Output {
public:
Rectangle (int a, int b) : Polygon(a,b), Output{"A Rectangle's area is: "} {}
int area () {
return width*height;
}
};
class Triangle: public Polygon, public Output {
public:
Triangle (int a, int b) : Polygon{a,b}, Output{"A Triangle's area is: "} {}
int area ()
{ return width*height/2; }
};
int main () {
Output * ptr1 = new Rectangle(4,5);
Output * ptr2 = new Triangle(4,5);
ptr1->print();
ptr2->print();
// Causes core dump.
delete ptr1;
delete ptr2;
return 0;
}
There are several major issues with this code:
First, you should not use multiple inheritance for this. It is completely unnecessary and will lead to very difficult to track down bugs.
Second, you do not need to test for nullptr before deleting a pointer - it is redundant as delete already does that.
Third, neither of your base classes has a virtual destructor. (your current error)
Forth, you are violating the Rule of 3 in your Output class (and likely will need to use it in all of them).
Fifth, assuming string means std::string. There is no reason for it to be a string* - just use std::string and avoid having to allocate and deallocate it.
I didn't fix your design issues, but your memory access and polymorphic issues are fixed here.
#include <iostream>
#include <string>
using namespace std;
class Polygon
{
protected:
int width, height;
public:
Polygon (int a, int b) : width(a), height(b) {}
virtual ~Polygon() { } // needed!
virtual int area() = 0;
};
class Output
{
private:
std::string myString; // no need to be a pointer
public:
Output() { }
Output(const string& s) : myString(s) { }
virtual ~Output() { } // also needed!
virtual int area() = 0;
void print () {
cout << myString << this->area() << '\n';
}
};
class Rectangle: public Polygon, public Output
{
public:
Rectangle (int a, int b) : Polygon(a,b), Output{"A Rectangle's area is: "} {}
int area () {
return width*height;
}
};
class Triangle: public Polygon, public Output
{
public:
Triangle (int a, int b) : Polygon{a,b}, Output{"A Triangle's area is: "} {}
int area ()
{ return width*height/2; }
};
int main ()
{
Output * ptr1 = new Rectangle(4,5);
Output * ptr2 = new Triangle(4,5);
ptr1->print();
ptr2->print();
// Causes core dump.
delete ptr1;
delete ptr2;
return 0;
}
EDIT: An example of a better way to implement the desired program can be found here.
Your Output and Polygon class destructors should be virtual also:
class Output {
private:
std::string* myString;
public:
// ...
virtual ~Output() {
// ^^^^^^^
}
};
Also note: Instead of using a std::string* pointer, you can simply use a std::string myString; member:
private:
std::string myString;
and leave behind bothering around with getting new string() and delete myString; right for any cases.
Related
Background
I am creating a Cpp parser using Bison and Flex and I stumbled upon a problem: In my parser, I require a vector of base class objects, let's say shapes. Depending on which derived class an object has, I need to access different members. Thus, my intend was to store unique_ptr in the vector. Then upon access, I could dynamically cast them to their derived type.
The Problem
However, I can't get Bison to handle the unique_ptrs correctly. No matter how I specify the parser.yy file, upon compilation I run into errors like
usr/include/c++/9/bits/stl_uninitialized.h:127:72: error: static assertion failed: result type must be constructible from value type of input range
According to this post Bison does not handle unique_ptrs well (as far as I understand Bison does not use std::move() internally) and I assume that this is still the case.
My Question
As I would like to keep the class hierarchy as it is and don't want to fix bugs within Bison itself: Is there an alternative to using unique_ptrs when casting from Base class to Derived class?
Code Example
In particular, I want something like the following to work without using unique_ptrs.
enum Shape_type{
SHAPE_TYPE_CIRCLE,
SHAPE_TYPE_TRIANGLE,
};
class Shape{
public:
enum Shape_type type;
Shape(enum Shape_type type){ this->type=type; }
virtual ~Shape(){}
};
class Circle: public Shape{
int r;
public:
int get_r(){ return this->r; }
Circle(int r):Shape(SHAPE_TYPE_CIRCLE){ this->r=r; }
};
int main(void){
std::vector<std::unique_ptr<Shape>> shapes;
std::unique_ptr<Shape> circle_ptr = std::make_unique<Circle>(42);
shapes.push_back(std::move(circle_ptr));
for(auto& s_ptr: shapes){
switch(s_ptr->type){
case SHAPE_TYPE_CIRCLE:
{
auto c = dynamic_cast<Circle&>(*s_ptr);
std::cout << "circle with r=" << c.get_r() << std::endl;
break;
}
default: {
std::cout << "other shape" << std::endl;
break;
}
}
}
return 0;
}
Any help is greately appreciated. Thanks in advance.
The polymorphic way would be (replacing non-copiable std::unique_ptr by std::shared_ptr):
class Shape{
public:
virtual ~Shape() = default;
virtual void draw() const = 0;
};
class Circle: public Shape
{
int r;
public:
explicit Circle(int r): r(r) {}
int get_r() const { return r; }
void draw() const override { std::cout << "circle with r=" << r << std::endl; }
};
class Square: public Shape
{
int side;
public:
explicit Square(int side): side(side) {}
int get_side() const { return side; }
void draw() const override { std::cout << "square with side=" << side << std::endl; }
};
int main()
{
std::vector<std::shared_ptr<Shape>> shapes { std::make_shared<Circle>(42) };
for (const auto& shape_ptr: shapes)
{
shape_ptr->draw();
}
return 0;
}
With std::variant, you might do
class Circle
{
int r;
public:
explicit Circle(int r): r(r) {}
int get_r() const { return r; }
void draw() const { std::cout << "circle with r=" << r << std::endl; }
};
class Square
{
int side;
public:
explicit Square(int side): side(side) {}
int get_side() const { return side; }
void draw() const { std::cout << "square with side=" << side << std::endl; }
};
using Shape = std::variant<Circle, Square>;
int main()
{
std::vector<Shape> shapes { Circle(42) };
for (const auto& shape: shapes)
{
std::visit([](const auto& shape){ shape.draw(); }, shape);
}
return 0;
}
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 an abstract parent class, let's call it A, and three child classes that inherit from it: a_B, a_C, and a_D. I have a sorting method that should be able to sort an array of any of these classes (a_B, a_C, or a_D) based on a rating property that they inherit from their parent, A.
I am having trouble implementing this, however.
Here's essentially what I have:
class A {
protected:
int rating;
A(int r) {
this->rating = r;
}
public:
int getRating() {
return rating;
}
virtual void abstractStuff() = 0;
}
class a_B : public A {
int property;
public:
a_B(int r, int p) : A(r) {
this->property = p;
}
void abstractStuff() {
cout << "a_B" << endl;
}
}
class a_C : public A {
float property;
public:
a_B(int r, float p) : A(r) {
this->property = p;
}
void abstractStuff() {
cout << "a_C" << endl;
}
}
class a_D : public A {
string property;
public:
a_B(int r, string p) : A(r) {
this->property = p;
}
void abstractStuff() {
cout << "a_D" << endl;
}
}
void sort(A* arr[]) {
//sort implementation
}
int main() {
a_B arr[5];
//code to give each element of arr unique properties
sort (arr); //doesn't work; this is where I'm kind of unclear about what to do
}
The last part, where I sort arr, is unclear to me. I'm not sure if I should pass a_B*, as a pointer, or maybe to cast it to type A, like (A) a_B or (A*) a_B or something of the sort.
edit:
The compiler gives me an error of an invalid conversion from a_B to A**.
Definitely your sort function takes an array of pointers to base class A, as the only argument. Probably, the idea is to achieve type erasure (to place in array elements of different dynamic types) and further you will be able to treat elements polymorphically. So, your arr argument will contain elements of type A*, and when you extract some element from array, you can extract its rating member for sorting purpose. Very important, you need to change to
a_B arr[5]; to A* arr[5];
also, every class constructor has the same name as class, so if we suppose that you made mistype, for example class a_D should looked like
class a_D : public A {
string property;
public:
a_D(int r, string p) : A(r) {
this->property = p;
}
void abstractStuff() {
cout << "a_D" << endl;
}
}
To mention also, that A as a base class, in implementation like yours, should have virtual destructor, or you will have leaks!!!
Further, to populate an array to be passed to sort, you need some kind of space allocated for array, on stack or heap (you choose stack), what ever, but be careful about lifetime issues, anyway. Once, when you have space for elements of an array of A* every element can be populated with A* which can be initialized with a_B* or a_C* or pointer to object of any derived class from A. Such an array, you can pass to sort function as argument, without any casting.
example code, you should be able to compile and run out of the box:
#include <iostream>
using namespace std;
class A {
protected:
int rating;
A(int r) {
this->rating = r;
}
public:
int getRating() {
return rating;
}
virtual ~A(){}
virtual void abstractStuff() = 0;
};
class a_B : public A {
int property;
public:
a_B(int r, int p) : A(r) {
this->property = p;
}
void abstractStuff() {
cout << "a_B" << endl;
}
};
class a_C : public A {
float property;
public:
a_C(int r, float p) : A(r) {
this->property = p;
}
void abstractStuff() {
cout << "a_C" << endl;
}
};
class a_D : public A {
string property;
public:
a_D(int r, string p) : A(r) {
this->property = p;
}
void abstractStuff() {
cout << "a_D" << endl;
}
};
template<class T, size_t N>
void printRatings(T*(&arr)[N]) {
for (size_t i=0; i<N; ++i) {
cout<< "rating["<< i <<"] = " << arr[i]->getRating() << "\n";
}
}
int main() {
A* arr[5];
a_B b(1,1);
a_C c(2,2.);
a_D d(3,"3");
arr[0] = &b;
arr[1] = &c;
arr[2] = &d;
arr[3] = &c;
arr[4] = &b;
printRatings (arr); //this works
return 0;
}
Note, that I used template function printRatings which takes
array of pointers to type T and deduces array size, so it can safely iterate through it.
the same idea you can use to make your sort function which will be like:
template<class T, size_t N>
void sort(T*(&arr)[N]) {
// sorting impl
}
and you will be able to pass A* arr[5] argument to it.
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
I have a weird problem. I made an example explaining what is the problem. I have 4 classes, one that gets a pointer to a class which is inherent to 2 others. Here is what it looks like :
The inherences classes:
class classA{
public:
classA(){}
virtual std::string getType(){return "classA";}
classA& operator=(const classA& classa) {return *this;}
};
class classB: public classA {
int b;
public:
classB(int n){b=n;}
virtual std::string getType() { return "classB"; }
void setB(const int b){this->b=b;}
int getB() const{return this->b;}
};
class classC: public classA {
int c;
public:
classC(int n){c=n;}
virtual std::string getType() { return "classC"; }
void setC(const int c){this->c=c;}
int getC() const{return this->c;}
};
The only important thing is the getType() function.
Here is now the class that get a pointer to classA
class superClass{
classA* _classA;
int nb;
public:
superClass(){nb=0;}
void addElement(classA& e){
classA *newTab=new classA[++nb]; // create tab as the same size than the other +1
for(int i=0;i<nb-1;i++)
newTab[i]=_classA[i]; // add element from the old class to the new one
newTab[nb-1]=e; // add the element
//delete[] _classA;
_classA=newTab; // now copy it to the class
//delete[] newTab;
}
classA* getClass() {return _classA;}
int getNb() const{return this->nb;}
void displayElements(){
for(int i=0;i<getNb();i++)
std::cout << _classA[i].getType() << std::endl;
}
};
addElemment() is a function that malloc a classA element with one space more, it is filled with the ancien elements then it adds the new element and here it goes. Is works BUT the problem is here. I don't use classA element, only its children. I want to add classB elements and classC elements the the superClass and get the class type with getType(); Here is the main file
int main(int argc, char const *argv[])
{
classB *classb = new classB(9);
classC *classc = new classC(10);
superClass super;
super.addElement(*classb);
super.displayElements();
// Display "classA" instead of "classB"
super.addElement(*classc);
super.displayElements();
// Display "classA" and "classA" instead "classB" and "classC"
//std::cout << classb->getType() << std::endl; // return ClassA
//std::cout << classc->getType() << std::endl; // return ClassA
return 0;
}
I just want my program displaying the right class, the child one class. The problem comes with addElement() I think. I tried to use virtual std::string getType()=0; but it still doesn't work, it changes nothing.
I also tried using template but changes nothing and does not work
My question : I want my program displaying the child class instead of classA everytime.
You should change declaration member _classA in superClass to the following: classA** _classA;.
So it would be like this:
class superClass
{
classA** _classA;
int nb;
public:
superClass():_classA(0) // you also should initialize this to avoid crash while first delete[] of this _classA
{
nb = 0;
}
~superClass() // also you should add destructor to free memory
{
for (int i = 0; i < nb; i++)
{
delete _classA[i];
_classA[i] = nullptr;
}
delete[] _classA;
_classA[i] = nullptr;
}
void addElement(classA& e)
{
int oldSize = nb;
nb++; // increment the size separately for clarity
classA **newTab = new classA*[nb]; // create tab as the same size than the other +1
for (int i = 0; i < oldSize; i++)
newTab[i] = _classA[i]; // add element from the old class to the new one
classA* newElement = new classA(e); // use the copy-constructor
newTab[oldSize] = newElement; // add the element
delete[] _classA; // now you can free it
_classA = newTab; // now copy it to the class
}
classA** getClass()
{
return _classA;
}
int getNb() const
{
return this->nb;
}
void displayElements()
{
for (int i = 0; i < getNb(); i++)
std::cout << _classA[i]->getType() << std::endl;
}
};
newTab is an array of classA. Therefore, it cannot contain classB objects, only classA objects.
newTab[nb-1]=e;
Here, if e refers to a classB object, this assignment slices the classB part away from it, so it becomes a classA object and can fit in the array. This is known as object slicing.