2

I am currently doing a project and learning about inheritance in c++. However I encountered a problem that I do not know how to solve.

I will give an example code because the real one is quite difficult to understand since it is in Spanish.

In musicalsymbol.h:

class MusicalSymbol {
public:
    MusicalSymbol();
    virtual ~MusicalSymbol();

    virtual qreal getX();
private:
    ...
};

musicalsymbol.cpp

MusicalSymbol::MusicalSymbol() {}
MusicalSymbol::~MusicalSymbol() {}

qreal MusicalSymbol::getX() {
    return -1;
}

Now I have a child class:

note.h

class Note : public MusicalSymbol{
public:
    Note();
    ~Note();
    qreal getX() override;
private:
    qreal x;

note.cpp

Note::Note() {}
Note::~Note() {}

qreal Note::getX() {
    return this->x;
}

Now I have another class where I have a vector of MusicalNote

std::vector < MusicalSymbol > tab_score;

I append elements to that vector that are of the class note (and other child classes) with push_back() but later when I try to access an element of the class like so:

tab_score[i].getX();

I always get -1 as an output, when I would like to get x from the Note class. What would be the best way of getting a correct value. Also it is possible to create a x value inside the parent class and modify it from the child class?

Edit: Thanks for the information about slicing, now I know why is not working but I still can't figure out how to solve it.

Thanks to everyone and let me know if there is something that it is not clear.

Juanjo
  • 79
  • 1
  • 8
  • Possible duplicate of [What is object slicing?](https://stackoverflow.com/questions/274626/what-is-object-slicing) – tkausl Aug 12 '19 at 16:29
  • Is this in `qt c++`? – Axiumin_ Aug 12 '19 at 16:30
  • @tkausl Thanks for the information, I did not know that term exists. But is there any way I can get a correct value? – Juanjo Aug 12 '19 at 16:32
  • @Axium yes, I am using qt but I am not sure if that is relevant in the context of the question – Juanjo Aug 12 '19 at 16:33
  • Why is it not working? (you said you know why it's not working) – Axiumin_ Aug 12 '19 at 16:35
  • @Axium I am getting -1 and I would like to get the value stored inside the Note class. Edit: Now I know that it is not working because of "object slicing" but I'm not sure how to solve it – Juanjo Aug 12 '19 at 16:37
  • @user4581301 but I am using a virtual method – Juanjo Aug 12 '19 at 16:38
  • Somehow I missed on the first read. You can only perform polymorphism through references. You need a `vector` of pointers, probably `std::unique_ptrs`. – user4581301 Aug 12 '19 at 16:38
  • I think that it could be solved if I could store my x value inside the parent class. Would that be possible? Since all of the child classes have a x value – Juanjo Aug 12 '19 at 16:41
  • @Juanjo If you call `getX()` on a `MusicalSymbol` object that is not a pointer or a reference to a `Note` object, it will just return -1. You cannot do runtime polymorphism with `virtual` functions in C++ without pointers or references. – Nikos C. Aug 12 '19 at 16:56

1 Answers1

3

The problem is that you are storing MusicalSymbol objects. If you want to use polymorphism you sould create a vector of MusicalSymbol * pointers.

Then you do tab_score[i]->getX().

If you keep the vector of MusicalSymbol objects, every time you try to add a child object to the vector, what you are really doing is creating a parent object that copies its members from the child object, losing the members that are exclusive to the child object. Then tab_score[i] is not a child object but a parent object, so when you call tab_score[i].getX() you are calling the parent class version.

Sergio
  • 88
  • 1
  • 6
  • Thank you for the answer but I was hoping to get an answer that did not involve changing the vector since I am using it inside my project quite often and it would mean I will have to change a lot of code. – Juanjo Aug 12 '19 at 16:44
  • 1
    And to avoid the issue of not cleaning up the vector, better use a vector of `unique_ptr` and use `emplace_back` instead of `push_back`. – Nikos C. Aug 12 '19 at 16:45
  • 3
    @Juanjo Runtime polymorphism in C++ **requires** pointers. It's not optional. You have to use pointers (preferably wrapped inside `unique_ptr`.) – Nikos C. Aug 12 '19 at 16:46
  • Recommendations: Make it absolutely clear that polymporphism only works through references, so the asker will have to perform a rewrite. Use the term [object slicing](https://stackoverflow.com/questions/274626/what-is-object-slicing) in the explanation. Typo: loosing -> losing – user4581301 Aug 12 '19 at 16:54
  • Agree with others - to use c++ polymorphism via the " virtual" functions you have to pass pointers. In your case, when you create an object of class "note" and push it into the vector, that push operation will implicitly downcast the object to "MusicalSymbol". However, if your vector is one of pointers, then the push operation will simply place that pointer in the vector and, when the getX() virtual function is called, when that pointer is dereferenced, it will give a "note" object and call the override virtual. – Adrian Mole Aug 12 '19 at 16:55
  • 1
    @Juanjo You have to make sure that the objects pointed by the elements in the array still exists when you dereference the pointers. – Sergio Aug 12 '19 at 17:20