Question

I am working in c++.

my class animation.h is the following:

class Animation
{
public:
    Animation(ofVec2f _startLoc, ofVec2f _endLoc, float _speed, float _accel);
    virtual ~Animation();
};

then in sceneMusic.h I have another class that calls animation class.

#include "animation.h"
class sceneMusic
{
    public:
        sceneMusic();
        virtual ~sceneMusic();
    private:
        Animation staveMotion;
};

and sceneMusic.cpp

sceneMusic::sceneMusic()
{
    staveImg.loadImage("./sceneMusic/stave_white.png");

    staveMotion = Animation(ofVec2f(29, -staveImg.height()), \
                            ofVec2f(29, 249), 1, 0.1);
}

The above gives the following (expected) error:

src/awards/sceneMusic.cpp|3|error: no matching function for call to ‘Animation::Animation()’|
src/awards/sceneMusic.cpp|5|note: candidates are:|
src/Animation.h|14|note: Animation::Animation(ofVec2f, ofVec2f, float, float)|
src/Animation.h|14|note:   candidate expects 4 arguments, 0 provided|

I read alot of threads that suggest I should use initializer lists and do in sceneMusic.cpp

sceneMusic::sceneMusic()
    :Animation(ofVec2f(29, -staveImg.height()), \
               ofVec2f(29, 249), 1, 0.1)
{
    staveImg.loadImage("./sceneMusic/stave_white.png");
}

or something similar. The problem is that the height of staveImg will only become available once the constructor will be executed.

Also the class sceneMusic does not inherit class animation, therefore I am not sure how the above would work. If I attempt to run the above I get

src/awards/sceneMusic.cpp|4|error: type ‘Animation’ is not a direct base of ‘sceneMusic’|
src/awards/sceneMusic.cpp|4|error: ‘((sceneMusic*)this)->sceneMusic::staveImg.ofImage_<unsigned char>::height’ cannot be used as a function|
src/awards/sceneMusic.cpp|5|error: no matching function for call to ‘Animation::Animation()’|
src/awards/sceneMusic.cpp|5|note: candidates are:|
...

What am I doing wrong ?

thank you for your help

Was it helpful?

Solution

Well, the issue with your second attempt is you'd need to do this:

sceneMusic::sceneMusic()
    :staveMotion(ofVec2f(29, -staveImg.height()), \
               ofVec2f(29, 249), 1, 0.1)

You specify the member names in the initializer lists. You specify a class name only when you are attempting to call a specific super-class constructor. Animation is not a super-class of sceneMusic.

The following "no matching function for call to Animation::Animation()" occurred for the same reason it would have occurred if you didn't have anything in your initializer list at all: the staveMotion member was still trying to use Animations default constructor (just like the default constructor is used when you declare a variable Animation a;), but Animation does not have a default constructor.

Correcting the error in the initializer list takes care of both errors.

By the way, your second error regarding height(): make sure there's actually a member function named height(). You aren't showing the code but that error seems to indicate that you actually have a member variable named height, not a function.

However, the above still won't fix your issue with having to call loadImage first (thanks chris for reminding me about that in comments).

The easiest solution to that is to revert to your first attempt, and simply provide a default (no parameter) constructor for Animation. As soon as you declare a non-default constructor, the compiler no longer generates a default constructor for you, and you have to explicitly declare/define Animation::Animation() to provide it. That way, staveMotion can be constructed with some default values (and won't have to be constructed in your initializer list) and then assigned to a proper value later.

A second option, by the way, that wouldn't require creation of temporary default Animations first (or perhaps more importantly, wouldn't require you to implement a default constructor that possibly breaks class invariants), would be to have staveImg be a member field of sceneMusic, give it a constructor that takes an image filename and loads the image, and declare it before staveMotion in the member list. You wouldn't need an Animation default constructor for this, and you could initialize everything in the initializer list:

sceneMusic :: sceneMusic () :
   staveImg("./sceneMusic/stave_white.png"),
   staveMotion(ofVec2f(29, -staveImg.height()), ofVec2f(29, 249), 1, 0.1)
{
}

A variation on that option is to construct the image ahead of time and pass it as a parameter to the sceneMusic constructor. This wouldn't require a new constructor fo staveImg.

A third option, which CantChooseUsernames brought up in the comments, is to make staveMotion a pointer. You can initialize it to NULL and construct a new Animation(...) when necessary without requiring a default constructor. If you do this, don't forget to delete it when you are done. An automatic pointer such as std::unique_ptr<Animation> or one of the other smart pointers (boost has some too) can make that easier on you.

OTHER TIPS

you need a default constructor class Animation since you provide parameter constructor ,the compiler would not generate one for you

Animation() {}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top