Class Inheritance

Soo, i m doing my homework and i have a question.
This is the code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
class Color{
private:
    double main_r, main_g, main_b;
public:
    static Color getMaxRed(Color carr[], int size);
    Color(double r_Color, double g_Color, double b_Color);
    Color(const Color& clr);
    double r() {return main_r;};
    double g() {return main_g;};
    double b() {return main_b;};
    string toString();
};
Color::Color(double r_Color, double g_Color, double b_Color)
{
    main_r = r_Color;
    main_g = g_Color;
    main_b = b_Color;
}
Color::Color(const Color& clr)
{
    main_r = clr.main_r;
    main_g = clr.main_g;
    main_b = clr.main_b;
    cout << "The second constructor was called.\n";
}
Color Color::getMaxRed(Color carr[], int size)
{
    double maxRed = carr[0].main_r;
    Color maxRedColor = carr[0];
    for(int i = 1; i < size; i++)
    {
        if(carr[i].main_r > maxRed)
        {
            maxRed = carr[i].main_r;
            maxRedColor = carr[i];
        }
    }
    return maxRedColor;
}
string Color::toString()
{
    ostringstream a;
    a << "(" << main_r << ", " << main_g << ", " << main_b << ")" << "\n";
    return a.str();
}

class Shape : public Color{
public:
    Shape(Color i_color);
    static int shapesCount();
    ~Shape();
    virtual string info();
    int id();
private:
    Color m_color;
    static int shapesCreated;
    static int shapesDestroyed;
    int shapeID;
};
int Shape::shapesCreated = 0;
int Shape::shapesDestroyed = 0;
Shape::Shape(Color i_color) , m_color(i_color)
{
    shapesCreated++;
    shapeID = shapesCreated;
}
Shape::~Shape()
{
    shapesDestroyed++;
}
int Shape::id(){
    return shapeID;
}
int Shape::shapesCount()
{
    return shapesCreated - shapesDestroyed;
}
string Shape::info(){
    return m_color.toString();
}
int main(){
    Color Red(0.1, 0.2, 0.3);
    Shape a(Red);
    Shape b(Red);
    Shape c(Red);
    c.~Shape();
    Shape d(Red);
    cout << a.id() << " " << d.id() << endl << Shape::shapesCount();
}


The Shape constructor is not working because i m inheriting the color class, if i m defining the shape class without ":public Color" "argument" it's working..
66:27: error: declaration of 'Shape::Shape(Color)' outside of class is not definition [-fpermissive]
66:38: error: expected constructor, destructor, or type conversion before '(' token

A comma shouldn't be used on line 66 regardless of any inheritance.
Shape::Shape(Color i_color) : m_color(i_color)

However, once you change that comma to colon, you still have a problem.

 In constructor 'Shape::Shape(Color)':
66:46: error: no matching function for call to 'Color::Color()'
66:46: note: candidates are:
23:1: note: Color::Color(const Color&)
23:1: note:   candidate expects 1 argument, 0 provided
17:1: note: Color::Color(double, double, double)
17:1: note:   candidate expects 3 arguments, 0 provided

This is because when you try to create a Shape, it needs to call the base class's constructor. Since you are not explicitly constructing the base class Shape, it tries to call the default constructor for Shape, which does not exist.

I'm not sure what your intentions are, but one way to "solve" this would be to also pass i_color into the base constructor, although you have duplication in data this way.

1
2
3
4
5
6
7
Shape::Shape(Color i_color)
: Color(i_color), // construct base class, Color
  m_color(i_color) // construct member variable, m_color
{
    shapesCreated++;
    shapeID = shapesCreated;
}


The design of your code is quite strange. You inherit from Color, but then have a Color as a member variable of shape. A shape is not a color, so inheritance doesn't make much sense here.
Last edited on
Ok, so i deleted the inheritation from Color, but now i m making another class (Circle), which have an inheritation from Shape. I need to override the string info() function so it will return the Shape's id and the shape color.
How can i define the constructor of Circle without making a data member which would be a Shape so i can still call the Shape's functions. I m new to this..
1
2
3
4
5
6
7
8
9
10
11
Circle::Circle(int x, int y, double r)
{
    x_coord = x;
    y_coord = y;
    radius = r;
}
string Circle::info(){
    ostringstream m_info;
    m_info << "Shape ID: " << // Shape::id() 
<< "\nShape Color: " << // Shape::m_color.toString();
}
If Circle inherits from Shape, a Shape needs to be constructed when a Circle is constructed. You can call the Shape's constructor through the initialization list

1
2
3
4
5
6
7
Circle::Circle(int x, int y, double r)
: Shape(Color(0.1, 0.2, 0.3)) // construct super class, Shape
{
    x_coord = x;
    y_coord = y;
    radius = r;
}


As for producing your desired string, here's an example of putting data into an ostringstream. Try to apply it to your info() function.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// Example program
#include <iostream>
#include <string>
#include <sstream>

std::string info() {
    int id = 12345;
    std::string color = "test color string";
    
    std::ostringstream info;
    info << "Shape ID: " << id << "\nShape Color: " << color;
    return info.str();
}

int main()
{
    std::cout << info() << std::endl;
}


Edit: It should be pretty similar syntax-wise to your existing toString function
1
2
3
4
5
string Circle::info(){
    ostringstream m_info;
    m_info << "Shape ID: " << Shape::id() << "\nShape Color: " << Shape::m_color.toString();
    return m_info;
}


Note that the "m_" style is usually used for member variables, for those that prefer that notation. Not local variables.

Also, I forgot to mention, you should't directly call the destructor (line 90). The whole point of a destructor is to be called automatically when an object goes out of scope.
Last edited on
How can i define the constructor of Circle without making a data member which would be a Shape so i can still call the Shape's functions


If you publiclly inherit from Shape, you ARE a Shape.

1
2
3
class Circle : public Shape
{
 ...


Now, a Circle IS a Shape. How can you call Shape's functions? They're Circle's functions! A Circle IS a Shape. Any function you could call on Shape, you can call on Circle, because Circle IS a Shape.

Thanks !
Another question (the last one)
How can i create an pointer array of Shapes that includes a Circle and a Rectangle.
Smth like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void printShapeArray(Shape* shapes, int size)
{
    for(int i = 0; i < size; i++)
    {
        cout << shapes[i]->info() << endl;
    }
}
int main(){
    Color Red(0.1, 0.2, 0.3);
    Color Blue(0.2, 0.3, 0.4);

    Circle cir(1,2,3, Red);
    Rectangle rec(2,3,4, Blue);

    Shape* a = {cir, rec};
    printShapeArray(a, 2);
}


I need to call the "info()" function from each subclass.
Edit:
I replaced
1
2
3
Shape* a = {cir, rec};
//to
Shape a[2] = {cir, rec};

Still don't know how to call the info function from each subclass.
Last edited on
"virtual" member functions do allow that:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <iostream>
#include <vector>
#include <string>

struct Shape {
    virtual std::string foo() { return "foo"; }
};

struct Circle : public Shape {
    std::string foo() { return "bar"; }
};

void printShapeArray(const std::vector<Shape*> & shapes)
{
    for ( auto s : shapes )
    {
        std::cout << s->foo() << '\n';
    }
}
int main(){
    Circle cir;
    Shape rec;

    std::vector<Shape*> a {&cir, &rec};
    printShapeArray( a );
}
To clarify, the reason why
Shape a[2] = {cir, rec};
does not work is because by trying to copy a Circle by value into a Shape, you are doing "object slicing". The information unique to the Circle is stripped away and only the Shape part is copied to the array.
https://stackoverflow.com/questions/274626/what-is-object-slicing

Polymorphism works with references or pointers to base classes; a Shape object itself cannot hold the information needed to do polymorphism. That's why keskiverto is using a container of Shape pointers, not Shapes.
Topic archived. No new replies allowed.