0

I have tried using pure virtual methods along with testing others answers on similar issues, but everything has continued to result in the same problem.

So I have this class Shape that acts as an interface declaring the virtual void Draw() method. This function is later overridden in three other classes for primitive shapes, and called from a class called GameObject, which calls a method Draw() in WireframeImage and in it's turn calls one of these primitive shape classes. When compiling I am presented with the following errors:

Error: LNK2001 unresolved external symbol "public: virtual void __thiscall Shape::Draw(class olc::PixelGameEngine,int,int,float,int,int,int)" (?Draw@Shape@@UAEXVPixelGameEngine@olc@@HHMHHH@Z)

File: GameObject.obj


Error: LNK2001 unresolved external symbol "public: virtual void __thiscall Shape::Draw(class olc::PixelGameEngine,int,int,float,int,int,int)" (?Draw@Shape@@UAEXVPixelGameEngine@olc@@HHMHHH@Z)

File: Shapes.obj


Error: LNK2001 unresolved external symbol "public: virtual void __thiscall Shape::Draw(class olc::PixelGameEngine,int,int,float,int,int,int)" (?Draw@Shape@@UAEXVPixelGameEngine@olc@@HHMHHH@Z)

File: WireframeImage.obj


Error: LNK1120 1 unresolved externals

Here's my code:

Shapes.h

#pragma once
#ifndef CLASS_SHAPES
#define CLASS_SHAPES

#include "olcPixelGameEngine.h"

class Shape
{
public:
    virtual void Draw(
        olc::PixelGameEngine engine,
        int originX,
        int originY,
        float scale,
        int rotation,
        int offsetX,
        int offsetY
    );
    olc::Pixel Color = olc::WHITE;
};


// Derived Shapes

class Line: public Shape {
private:
    Point P1, P2;
   public:
        Line();
        Line(Point, Point, olc::Pixel);
        void Draw(olc::PixelGameEngine engine, int originX, int originY, float scale, int rotation, int offsetX, int offsetY) override;
};

class Triangle: public Shape {
private:
    Line L1, L2, L3;
   public:
        Triangle();
        Triangle(Point, Point, Point, olc::Pixel);
        void Draw(olc::PixelGameEngine engine, int originX, int originY, float scale, int rotation, int offsetX, int offsetY) override;
};

class Rectangle: public Shape {
private:
    Line L1, L2, L3, L4;
   public:
        Rectangle();
        Rectangle(Point, Point, Point, Point, olc::Pixel);
        void Draw(olc::PixelGameEngine engine, int originX, int originY, float scale, int rotation, int offsetX, int offsetY) override;
};


#endif // !CLASS_SHAPES

Shapes.cpp

#include "Shapes.h"

Line::Line() { }
Line::Line(Point p1, Point p2, olc::Pixel color = olc::WHITE) {
    P1 = p1;
    P2 = p2;
    Color = color;
}
void Line::Draw(olc::PixelGameEngine engine, int originX, int originY, float scale, int rotation, int offsetX, int offsetY) {
    engine.DrawLine(P1.X, P1.Y, P2.X, P2.Y, Color);
}

Triangle::Triangle() { }
Triangle::Triangle(Point p1, Point p2, Point p3, olc::Pixel color = olc::WHITE) {
    L1 = {p1, p2, color};
    L2 = {p2, p3, color};
    L3 = {p3, p1, color};
    Color = color;
}
void Triangle::Draw(olc::PixelGameEngine engine, int originX, int originY, float scale, int rotation, int offsetX, int offsetY) {
    L1.Draw(engine, originX, originY, scale, rotation, offsetX, offsetY);
    L2.Draw(engine, originX, originY, scale, rotation, offsetX, offsetY);
    L3.Draw(engine, originX, originY, scale, rotation, offsetX, offsetY);
}

Rectangle::Rectangle() { }
Rectangle::Rectangle(Point p1, Point p2, Point p3, Point p4, olc::Pixel color = olc::WHITE) {
    L1 = {p1, p2, color};
    L2 = {p2, p3, color};
    L3 = {p3, p4, color};
    L4 = {p4, p1, color};
    Color = color;
}
void Rectangle::Draw(olc::PixelGameEngine engine, int originX, int originY, float scale, int rotation, int offsetX, int offsetY) {
    L1.Draw(engine, originX, originY, scale, rotation, offsetX, offsetY);
    L2.Draw(engine, originX, originY, scale, rotation, offsetX, offsetY);
    L3.Draw(engine, originX, originY, scale, rotation, offsetX, offsetY);
    L4.Draw(engine, originX, originY, scale, rotation, offsetX, offsetY);
}

WireframeImage.h

#pragma once
#ifndef CLASS_WIREFRAMEIMAGE
#define CLASS_WIREFRAMEIMAGE

#include <iostream>

#include "Shapes.h"
#include "SymmetryMode.h"

class WireframeImage
{
private:
    std::vector<Triangle>   _shapes;
    SymmetryMode        _symmetryMode;
public:
    WireframeImage();
    WireframeImage(std::string file);
    void Load(std::string file);
    void Draw(olc::PixelGameEngine engine, int x, int y, float scale, int rotation, int offsetX, int offsetY);
};

#endif // !CLASS_WIREFRAMEIMAGE

WireframeImage.cpp

#include "WireframeImage.h"
#include "Shapes.h"

#include <string>
#include <iostream>

WireframeImage::WireframeImage() { }
WireframeImage::WireframeImage(std::string file) {
    Load(file);
}

void WireframeImage::Load(std::string file) {
    // Code ...
}

void WireframeImage::Draw(olc::PixelGameEngine engine, int originX, int originY, float scale, int rotation, int offsetX, int offsetY) {
    for(Shape s : _shapes) {
        s.Draw(engine, originX, originY, scale, rotation, offsetX, offsetY);
    }
}

GameObject.h

#include "GameObject.h"

GameObject::GameObject() { }
GameObject::GameObject(olc::PixelGameEngine engine, WireframeImage sprite, int x, int y) {
    _engine = engine;
    Sprite = sprite;
    X = x;
    Y = y;
    Rotation = 0;
}
void GameObject::Draw() {
    this->Sprite.Draw(this->_engine, this->_engine.ScreenWidth()/2, this->_engine.ScreenHeight()/2, Scale, Rotation, X, Y);
}

I'm using Visual Studio 2017 if that's to any help.

William R.
  • 145
  • 1
  • 11
  • 1
    Your linker is correct. You did not implement the function that is listed `Shape::Draw()` Did you want that to be pure virtual or have an implementation? – drescherjm Feb 28 '20 at 21:50
  • 1
    TL;DR of the dupeL: `for(Shape s : _shapes)` slices the triangles that are stored in `_shapes`. You need `for(Shape& s : _shapes)` so you have a reference an no slicing which will allow the virtual mechanics to work. – NathanOliver Feb 28 '20 at 21:51
  • 1
    Also, if you have a virtual function in an interface that you are not going to implement, you should consider making it pure virtual by adding ` = 0;` after the declaration so you can't accidentally make objects of the interface type. – NathanOliver Feb 28 '20 at 21:52
  • 1
    Is your Shape::Draw function not missing =0 ? You've written it's declaration but there is no definition. To make function abstract you have to add =0 at the end – Eric Feb 28 '20 at 21:54
  • So, All errors were fixed by first restarting Visual Studio (which probably was unnecessary) and adding `= 0` to the `Shape::Draw`. Thanks! – William R. Feb 28 '20 at 21:56
  • @NathanOliver I actually changed my code after this post, so that I have `WireframeImage::_shapes` of type `std::vector` and iterating using a `for(Shape* s : _shapes) { (*s).Draw( ... ); }` Is this a good implementation by standards? – William R. Feb 28 '20 at 22:00
  • @WilliamR. If you are using `new` to allocate those pointers then no. Use `std::vector>` or `std::vector>` instead so you don't risk a memory leak. – NathanOliver Feb 28 '20 at 22:04

0 Answers0