Link to home
Start Free TrialLog in
Avatar of sally1980
sally1980

asked on

no appropriate default constructor available.

Thanks for your comment, now I know that if I accept is (Position p[]) then I should use pointer to a Position* , if (float a[]) then I should use float*. And now I know that return an array. Thanks! 

Now I got another question I try to write the class MyOpenGLScene which inherits publicly from OpenGLScene. I try to add to the class an array which stores pointer to triangle and write a constructor which will accept the following parameters:
The name of the scene (as a char*), the width, the height , the color depth and a fullscreen flage(FALSE).
So I write like this:
 MyOpenGLScene::MyOpenGLScene (char* title, int width, int height, int bits, bool fullscreenflag)
{
      //this->title = title;
      //this->width = width;
      //this->heigh = heigh;
      //this->bits = bits;
      //this->fullscreenflag = fullscreenflag;
}
Then I got this error: C2512: 'OpenGLScene' : no appropriate default constructor available. So I don’t understand what going wrong, because I think the way I write is fine. I don’t know this error how to fix it, because I also new with C++, so can anyone explain to me why I will got this error? And what should I do if I meet with this kind of error again.

Following is my all class and code.
OpenGLScene.h
#define FALSE 0

class OpenGLScene {      
      HGLRC hRC;
      HWND hWnd;
      HINSTANCE hInstance;
      HDC hDC;
      BOOL done;
      bool fullscreen;
      MSG msg;
      GLvoid ReSizeGLScene(GLsizei width, GLsizei height);
      int InitGL(GLvoid);
      BOOL CreateGLWindow(char* title, int width, int height, int bits, bool fullscreenflag);
      
public:
      OpenGLScene (char* title, int width, int height, int bits, bool fullscreenflag);
      GLvoid KillGLWindow(GLvoid);
      virtual void addTriangle (Triangle *T) = 0;
      virtual int DrawGLScene(GLvoid) = 0;
      virtual void DrawTriangle (Triangle *T) = 0;
      int start ();
};

#endif


MyOpenGLScene.cpp
#include "OpenGLScene.h"

class MyOpenGLScene: public OpenGLScene
{
      Triangle* T;
      //char* title;
      //int width, heigh, bits;
      //bool fullscreenflag;

  public:
    //MyOpenGLScene (char* title, int width, int height, int bits, bool fullscreenflag);
      MyOpenGLScene (char* title, int width, int height, int bits, bool fullscreenflag);
      void addTriangle (Triangle *T);
      int DrawGLScene(GLvoid);
      void DrawTriangle (Triangle *T);
};

Triangle.h
#include "Position.h"
class Triangle
{
      float red,green,blue,point;
      Position pos[3];
            
public:
      Triangle (Position p[]);
      //~Triangle();
      void setColor(float red,float green,float blue);
      float getRed();
      float getGreen();
      float getBlue();
      Position* getVertices();
};

Hope someone can help me solve my problem. Thanks

From:sally
ASKER CERTIFIED SOLUTION
Avatar of Exceter
Exceter
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of efn
efn

You also have to add a constructor to the OPenGLScene base class, as I demonstrated above, because it does not define a default constructor either. This is necessary because the constructor for the parent classes are called before the constructor for the derived class. For example,

class test1
{
      public:
            test1(int x){}
};

class test2 : public test1
{
      public:
            test2(){}
};

Will generate an error message similar to this, deending on your compiler,

Error E2251 C:\CPP\Test.cpp 16: Cannot find default constructor to initialize base class 'test1' in function test2::test2()

Similarly,

class test1
{
      public:
            test1(){}
};

class test2 : public test1
{
      public:
            test2(int x){}
};

Will generate an error similar to this,

>> Error E2285 C:\CPP\Test.cpp 24: Could not find a match for 'test2::test2()' in function main()

So, in actuality, you need to define a default constructor in both the base class and in the derived class.

Cheers!
Exceter
Just to clarify, Exceter and I have provided two different solutions--you can use either one, depending on what you need in the code that uses this class.  If you really need a default constructor, you can define one, as Exceter suggested, and if you don't really need a default constructor, you can use the constructor you already have, as I suggested.

--efn
>> Exceter and I have provided two different solutions

Not really. I added a default constructor in the base class you suggesed adding one in the derived class, or not using a default constructor.

>> If you really need a default constructor, you can define one, as Exceter suggested, and if you don't really need a default constructor, you can use the constructor you already have, as
>> I suggested.

That's incorrect. The definition of a default constructor in the base class is manditory if you want to derive another class from it. The code will not compile if the base class does not have a default constructor, even if the dereived class does. For example,

class test1
{
    public:
         test1(int x){}
};

class test2 : public test1
{
    public:
          test2(){}
         test2(int y){}
};

Will give you an error similar to this,

Error E2251 C:\CPP\Test.cpp 16: Cannot find default constructor to initialize base class 'test1' in function test2::test2()
Error E2251 C:\CPP\Test.cpp 17: Cannot find default constructor to initialize base class 'test1' in function test2::test2(int)

The default constructor is necessary to construct the base class members before the derived class's consturctor is called and in like manner the destructor of test2 will be called before the destructor for test1. For example,

class test1
{
    public:
         test1(){ cout << "test1 being constructed." << endl; }
         ~test1(){ cout << "test1 being destroyed." << endl; }
};

class test2 : public test1
{
    public:
          test2(){ cout << "test2 being constructed." << endl; }
          ~test2(){ cout << "test2 being destroyed." << endl; }
};

...

test2 t;

-- output --
test1 being constructed.
test2 being constructed.
test2 being destroyed.
test1 being destroyed.

Therefore, the default constructor is required in the base class, as I demonstrated in my initial post, just so you can use the constructor that is already defined in MyOpenGLScene. If you want you can also define a default constructor for MyOpenGLScene but you dont have to. Although it is bad form not to do so.

Cheers!
Exceter
efn>> Exceter and I have provided two different solutions

Exceter>> Not really. I added a default constructor in the base class you suggesed adding one in the derived class, or not using a default constructor.

Yes, really.  I wasn't ingenious enough to suggest adding a default constructor, so I just suggested using the existing parameterized constructor.  However, my solution was defective because I guessed that the message was coming from an attempt to construct a derived object and I didn't notice that the derived class was trying to use a nonexistent default constructor for the base class.  So they really are two different solutions, mine just wouldn't work, and my statement that either would work was bogus.  Sorry, Sally!

efn>> If you really need a default constructor, you can define one, as Exceter suggested, and if you don't really need a default constructor, you can use the constructor you already have, as
efn>> I suggested.

Exceter>>That's incorrect. The definition of a default constructor in the base class is manditory if you want to derive another class from it. The code will not compile if the base class does not have a default constructor, even if the dereived class does.

I now agree that the original parameterized derived class constructor had a problem in itself and using it would not get the code to compile.  However, I don't agree with the statement that the base class must have a default constructor.  It's true that Exceter's example will not compile and it's true that adding a default constructor to the base class will get it to compile.  However, it's not true that this is the only way to get it to compile.  Here's another way:

class test2 : public test1
{
    public:
            test2() : test1(0){}
            test2(int y) : test1(y){}
};

This compiles without a default constructor in the base class test1.  Similarly, Sally could fix her code by having MyOpenGLScene initialize OpenGLScene in its initialization list.  Once again, we have a choice of two valid solutions!  Unless I blew it again.

--efn
>> However, I don't agree with the statement that the base class must have a default constructor.

True, you can do it that way. However, I think that your second example, although legal, has a design flaw because you are then required to do this in every class you derive from test1. This is annoying and easily forgotten. Also, the overhead of passing parameters to the constructor is probably slower than hardcoding them into the initialization list of a default constructor.

Exceter
No comment has been added lately, so it's time to clean up this TA.
I will leave the following recommendation for this question in the Cleanup topic area:

Accept: Exceter {http:#9662191}

Please leave any comments here within the next seven days.
PLEASE DO NOT ACCEPT THIS COMMENT AS AN ANSWER!

Tinchos
EE Cleanup Volunteer