Base and derived class in one header

2019-07-23 21:26发布

问题:

I want to put two clasess in one header file. The one is a base class and the second is derived form this base class, what I mean is something like this:

class Drawable{
public:

  Drawable();

  void setPosition(math::Vector3 position);

  void draw();

};

class Box: public Drawable{} ;

But I get error "undefined reference to `Drawable::Drawable()' ". In source file I have:

class Drawable {
public:
    math::Vector3 position;
    math::Vector3 rotation;

    Drawable() {
        position = math::Vector3(1.0, 1.0, 1.0);
        rotation = math::Vector3(0.0, 0.0, 0.0);
    }

    void setPosition(math::Vector3 position) {
        this->position = position;
    }

    void draw() {
    }
};

class Box: public Drawable {
public:
    void draw() {

        glBegin(GL_TRIANGLES);
        drawPoint(this->position + math::Vector3(1.0f, 1.0f, 1.0f));
        drawPoint(this->position + math::Vector3(-1.0f, 1.0f, 1.0f));
        drawPoint(this->position + math::Vector3(-1.0f, 1.0f, 1.0f));

        drawPoint(this->position + math::Vector3(1.0f, 1.0f, 1.0f));
        drawPoint(this->position + math::Vector3(1.0f, 1.0f, -1.0f));
        drawPoint(this->position + math::Vector3(1.0f, -1.0f, 1.0f));
        glEnd();
    }
};

So it seems to me impossible to accomplish this because the derivated class in header not already knows about the constructor of the base class. Am I right?

回答1:

You need to do something like this:

example.h

class Drawable 
{ 
    public:

    Drawable();

    void setPosition(math::Vector3 position);

    virtual void draw();

    math::Vector3 position;
    math::Vector3 rotation;
};

class Box: public Drawable
{
    public:
    virtual void draw();
};

example.cpp

#include "example.h"

Drawable::Drawable() {
    position = math::Vector3(1.0, 1.0, 1.0);
    rotation = math::Vector3(0.0, 0.0, 0.0);
}

void Drawable::setPosition(math::Vector3 position) {
    this->position = position;
}

void Drawable::draw() {
}

void Box::draw() {

    glBegin(GL_TRIANGLES);
    drawPoint(this->position + math::Vector3(1.0f, 1.0f, 1.0f));
    drawPoint(this->position + math::Vector3(-1.0f, 1.0f, 1.0f));
    drawPoint(this->position + math::Vector3(-1.0f, 1.0f, 1.0f));

    drawPoint(this->position + math::Vector3(1.0f, 1.0f, 1.0f));
    drawPoint(this->position + math::Vector3(1.0f, 1.0f, -1.0f));
    drawPoint(this->position + math::Vector3(1.0f, -1.0f, 1.0f));
    glEnd();
}

Header defines:

  • Constructor/Destructor signatures
  • Member variables
  • Member function signatures

Source defines

  • Constructor/Destructor implementation
  • Member function implementation

Note: Use a scope resolution operator :: to refer to the class members.



回答2:

  1. All data members (like math::Vector3 position;) MUST be defined ONLY in the header file, NOT in the cpp.
  2. The definition of a method in the cpp file is: return_type class_name::function_name (parameters) { ... }
  3. draw should be virtual in your case. Even, maybe, pure virtual (like void draw() = 0; in the base class and declared and implemented in the derived).

Example:

///////////////////////////////////////////
// header
class A
{
public:
    A();
    void f();
private:
    int x;
};

/////////////////////////////////////////// 
// cpp
A::A() 
{ 
    /* constructor impl */ 
}

void A::f() 
{ 
    /* impl */ 
}


回答3:

You would implement your methods in the source file like this:

void Drawable :: setPositon(...){ //do stuff };

You are declaring a new class with the same name than in the header!



回答4:

also, seeing as you have a setter function for your position member, you should probably make it private, and declare & define a getter as well:

class Drawable{
private:
    math::Vector3 position;
    math::Vector3 rotation;
public:
    Drawable();
    void setPosition(math::Vector3 position);
    math::Vector3 getPosition();
    void setRotation(math::Vector3 rotation);
    math::Vector3 getRotation();
    void draw();
};

with your current implementation, calling the setter would be somewhat redundant, as you could just access the member directly instead of using a setter function:

Drawable d;
d.position = math::Vector3(0,0,0);      //both do the
d.setPosition(math::Vector3(0,0,0));    //same thing