jeudi 17 avril 2014

Classe C++ Parent avec des méthodes virtuelles implémentée dans 2 classes différentes enfant - Stack Overflow


It was hard to make the title very clear about the subject, but I will try to explain the context (and there is some of the code down below). Note: I have seen similar questions answered, but they only treated the cases with 1 child class. So they didn't really help in my case, because I have 2 child classes.


Context: I have a parent class Shape that has 2 child: Circle and Square. I will have a vector of Shape objects, but these Shape objects will actually only be either Circle objects or Square objects. I need the Circle and Square classes to have the same parent class so that I can store them both in the same vector.


The trick is that I will need to use the Shape objects in the vector to call methods implemented in either the Circle class or the Square class, therefore, I need to have a "virtual" version of those methods in the parent class Shape.


Here is a simplified part of the code for my classes:


Shape.h :


class Shape{
public:
std::string getColor();

virtual int getRadius() = 0; //Method implemented in Circle
virtual int getHeight() = 0; //Method implemented in Square
virtual int getWidth() = 0; //Method implemented in Square

protected:
std::string color;
};

class Circle : public Shape{
public:
int getRadius();

private:
int radius;
};

class Square : public Shape{
public:
int getHeight();
int getWidth();

private:
int height;
int width;
};

In Shape.cpp I have something like this:


std::string Shape::getColor(){
return color;
}

int Circle::getRadius(){
return radius;
}

int Square::getHeight(){
return height;
}

int Square::getWidth(){
return width;
}

The errors occurs in the main.cpp when I want to create Circle and Square objects:


Circle *c = new Circle(...);//Error: cannot instantiate abstract class
//pure virtual function "Shape::getHeight" has no overrider
//pure virtual function "Shape::getWidth" has no overrider


Square *s = new Square(...);//Error: cannot instantiate abstract class
//pure virtual function "Shape::getRadius" has no overrider

So it seems like I would need a declaration of "getRadius" in the Square class and a declaration of "getHeight" and "getWidth" in the Circle class...


I tried adding them with virtual, but that makes Circle and Square abstract classes, so I can't create any objects with them.


Is there a way to make this work?


This is my first question posted on stackoverflow. I hope everything is clear. Thanks for the help!




Your virtual methods are not really good candidates for virtual methods because they have specific functionality for one class but no use for the other.


Good example of virtual method would be something implemented by each class but with different functionality or result, like virtual int area() or virtual bool intersects( Shape * otherShape ) and so on.


Anyway, this is how you would get your code compiled (with some extras):


shape:


class Shape{
public:
std::string getColor();

Shape() {}
virtual ~Shape() {}

virtual int getRadius() { return 0; } // no pure virtual
virtual int getHeight() { return 0; } // no pure virtual
virtual int getWidth() { return 0; } // no pure virtual

protected:
std::string color;
};


class Circle : public Shape {
public:
Circle( int r )
: Shape()
, radius( r )
{}

Circle() : Circle( 0 ) {}
~Circle() { std::cout << __PRETTY_FUNCTION__ << std::endl; }

int getRadius() override { return radius; };

private:
int radius;
};

square:


class Square : public Shape {
public:
Square( int h, int w )
: Shape()
, height( h )
, width( w )
{}

Square() : Square( 0, 0 ) {}
~Square() { std::cout << __PRETTY_FUNCTION__ << std::endl; }

int getHeight() override { return height; }
int getWidth() override { return width; }

private:
int height;
int width;
};

test:


int main() {
using shapes = std::vector< Shape * >;

shapes s;
s.push_back( new Circle( 10 ) );
s.push_back( new Square() );
s.push_back( new Square( 1, 3 ) );
s.push_back( new Circle() );

for ( Shape * sh : s ) {
std::cout
<< " r " << sh->getRadius()
<< " h " << sh->getHeight()
<< " w " << sh->getWidth()
<< std::endl;
}

for ( Shape * sh : s ) { delete sh; } s.clear();
}

output:


r 10 h 0 w 0
r 0 h 0 w 0
r 0 h 1 w 3
r 0 h 0 w 0
virtual Circle::~Circle()
virtual Square::~Square()
virtual Square::~Square()
virtual Circle::~Circle()

Here is a better use of virtual methods with area example:


#include <iostream>
#include <vector>

struct Shape {
Shape() {}
virtual ~Shape() {}

virtual double area() = 0;
};

extend with different area implementation:


struct Circle : public Shape {
Circle( int r )
: Shape()
, radius( r )
{}

Circle() : Circle( 0 ) {}
~Circle() { std::cout << __PRETTY_FUNCTION__ << std::endl; }

virtual double area() override { return radius * radius * 3.14; }

int radius;
};

struct Square : public Shape {
Square( int h, int w )
: Shape()
, height( h )
, width( w )
{}

Square() : Square( 0, 0 ) {}
~Square() { std::cout << __PRETTY_FUNCTION__ << std::endl; }

virtual double area() override { return height * width; }

int height;
int width;
};

test


int main() {
using shapes = std::vector< Shape * >;

shapes s;
s.push_back( new Circle( 1 ) );
s.push_back( new Square( 1, 1 ) );
s.push_back( new Square( 2, 3 ) );
s.push_back( new Circle( 2 ) );

for ( Shape * sh : s ) {
std::cout << sh->area() << std::endl;
}

for ( Shape * sh : s ) { delete sh; } s.clear();
}

output:


3.14
1
6
12.56
virtual Circle::~Circle()
virtual Square::~Square()
virtual Square::~Square()
virtual Circle::~Circle()



I hope you know the difference between pure virtual and just virtual functions. Pure virtual functions are essentially placeholder functions with no body. Your base class of shape is better suited for plain virtual functions, which are functions that can but don't have to be changed in subclasses. Take out the = 0 part in the function declaration to make the functions just plain virtual functions.




This should get you headed in the right direction. By making your members not pure virtual you can implement them if you want in the derived classes but you do not have to.


class Shape{
public:
std::string getColor();

virtual int getRadius(); //Method implemented in Circle
virtual int getHeight(); //Method implemented in Square
virtual int getWidth(); //Method implemented in Square

protected:
std::string color;
};

class Circle : public Shape{
public:
int getRadius();

private:
int radius;
};

class Square : public Shape{
public:
int getHeight();
int getWidth();

private:
int height;
int width;
};


It was hard to make the title very clear about the subject, but I will try to explain the context (and there is some of the code down below). Note: I have seen similar questions answered, but they only treated the cases with 1 child class. So they didn't really help in my case, because I have 2 child classes.


Context: I have a parent class Shape that has 2 child: Circle and Square. I will have a vector of Shape objects, but these Shape objects will actually only be either Circle objects or Square objects. I need the Circle and Square classes to have the same parent class so that I can store them both in the same vector.


The trick is that I will need to use the Shape objects in the vector to call methods implemented in either the Circle class or the Square class, therefore, I need to have a "virtual" version of those methods in the parent class Shape.


Here is a simplified part of the code for my classes:


Shape.h :


class Shape{
public:
std::string getColor();

virtual int getRadius() = 0; //Method implemented in Circle
virtual int getHeight() = 0; //Method implemented in Square
virtual int getWidth() = 0; //Method implemented in Square

protected:
std::string color;
};

class Circle : public Shape{
public:
int getRadius();

private:
int radius;
};

class Square : public Shape{
public:
int getHeight();
int getWidth();

private:
int height;
int width;
};

In Shape.cpp I have something like this:


std::string Shape::getColor(){
return color;
}

int Circle::getRadius(){
return radius;
}

int Square::getHeight(){
return height;
}

int Square::getWidth(){
return width;
}

The errors occurs in the main.cpp when I want to create Circle and Square objects:


Circle *c = new Circle(...);//Error: cannot instantiate abstract class
//pure virtual function "Shape::getHeight" has no overrider
//pure virtual function "Shape::getWidth" has no overrider


Square *s = new Square(...);//Error: cannot instantiate abstract class
//pure virtual function "Shape::getRadius" has no overrider

So it seems like I would need a declaration of "getRadius" in the Square class and a declaration of "getHeight" and "getWidth" in the Circle class...


I tried adding them with virtual, but that makes Circle and Square abstract classes, so I can't create any objects with them.


Is there a way to make this work?


This is my first question posted on stackoverflow. I hope everything is clear. Thanks for the help!



Your virtual methods are not really good candidates for virtual methods because they have specific functionality for one class but no use for the other.


Good example of virtual method would be something implemented by each class but with different functionality or result, like virtual int area() or virtual bool intersects( Shape * otherShape ) and so on.


Anyway, this is how you would get your code compiled (with some extras):


shape:


class Shape{
public:
std::string getColor();

Shape() {}
virtual ~Shape() {}

virtual int getRadius() { return 0; } // no pure virtual
virtual int getHeight() { return 0; } // no pure virtual
virtual int getWidth() { return 0; } // no pure virtual

protected:
std::string color;
};


class Circle : public Shape {
public:
Circle( int r )
: Shape()
, radius( r )
{}

Circle() : Circle( 0 ) {}
~Circle() { std::cout << __PRETTY_FUNCTION__ << std::endl; }

int getRadius() override { return radius; };

private:
int radius;
};

square:


class Square : public Shape {
public:
Square( int h, int w )
: Shape()
, height( h )
, width( w )
{}

Square() : Square( 0, 0 ) {}
~Square() { std::cout << __PRETTY_FUNCTION__ << std::endl; }

int getHeight() override { return height; }
int getWidth() override { return width; }

private:
int height;
int width;
};

test:


int main() {
using shapes = std::vector< Shape * >;

shapes s;
s.push_back( new Circle( 10 ) );
s.push_back( new Square() );
s.push_back( new Square( 1, 3 ) );
s.push_back( new Circle() );

for ( Shape * sh : s ) {
std::cout
<< " r " << sh->getRadius()
<< " h " << sh->getHeight()
<< " w " << sh->getWidth()
<< std::endl;
}

for ( Shape * sh : s ) { delete sh; } s.clear();
}

output:


r 10 h 0 w 0
r 0 h 0 w 0
r 0 h 1 w 3
r 0 h 0 w 0
virtual Circle::~Circle()
virtual Square::~Square()
virtual Square::~Square()
virtual Circle::~Circle()

Here is a better use of virtual methods with area example:


#include <iostream>
#include <vector>

struct Shape {
Shape() {}
virtual ~Shape() {}

virtual double area() = 0;
};

extend with different area implementation:


struct Circle : public Shape {
Circle( int r )
: Shape()
, radius( r )
{}

Circle() : Circle( 0 ) {}
~Circle() { std::cout << __PRETTY_FUNCTION__ << std::endl; }

virtual double area() override { return radius * radius * 3.14; }

int radius;
};

struct Square : public Shape {
Square( int h, int w )
: Shape()
, height( h )
, width( w )
{}

Square() : Square( 0, 0 ) {}
~Square() { std::cout << __PRETTY_FUNCTION__ << std::endl; }

virtual double area() override { return height * width; }

int height;
int width;
};

test


int main() {
using shapes = std::vector< Shape * >;

shapes s;
s.push_back( new Circle( 1 ) );
s.push_back( new Square( 1, 1 ) );
s.push_back( new Square( 2, 3 ) );
s.push_back( new Circle( 2 ) );

for ( Shape * sh : s ) {
std::cout << sh->area() << std::endl;
}

for ( Shape * sh : s ) { delete sh; } s.clear();
}

output:


3.14
1
6
12.56
virtual Circle::~Circle()
virtual Square::~Square()
virtual Square::~Square()
virtual Circle::~Circle()


I hope you know the difference between pure virtual and just virtual functions. Pure virtual functions are essentially placeholder functions with no body. Your base class of shape is better suited for plain virtual functions, which are functions that can but don't have to be changed in subclasses. Take out the = 0 part in the function declaration to make the functions just plain virtual functions.



This should get you headed in the right direction. By making your members not pure virtual you can implement them if you want in the derived classes but you do not have to.


class Shape{
public:
std::string getColor();

virtual int getRadius(); //Method implemented in Circle
virtual int getHeight(); //Method implemented in Square
virtual int getWidth(); //Method implemented in Square

protected:
std::string color;
};

class Circle : public Shape{
public:
int getRadius();

private:
int radius;
};

class Square : public Shape{
public:
int getHeight();
int getWidth();

private:
int height;
int width;
};

0 commentaires:

Enregistrer un commentaire