Solved

multiple definition of method

Posted on 2014-12-09
8
145 Views
Last Modified: 2014-12-10
class Shape
{

public:
    BLOCK blocks[4];
    SHAPE_TYPE whoami;
    friend Table;
    Table *tbl;
    // Default constructor
    Shape() {};
    //Shape(Table *tbl) { this->tbl = tbl;}
public:
    // non-virtual
    void DrawSingleBlock(BLOCK block)
    {
        RECT rect;
        HBRUSH brush = CreateSolidBrush(RGB(0, 255, 0));

        rect.top    = (*tbl).initial_point.y + block.Y * (*tbl).cell.height;
        rect.left   = (*tbl).initial_point.x + block.X * (*tbl).cell.width;
        rect.bottom = rect.top + tbl->cell.height;
        rect.right  = rect.left + tbl->cell.width;

        FillRect(tbl->hdc, &rect, brush);
    }

    // virtual
    virtual void Draw(void) {};
    virtual void Rotate(ROTATE_DIR rdir){ return; };
    virtual bool isRotatable(ROTATE_DIR rdir){ return false;};
};

class LineShape : public Shape
{
public:
    LineShape();
    LineShape(Table *tbl, BLOCK start_block)
    {
        this->tbl = tbl;
    for (int i = 0; i < 4; i++)
    {
        this->blocks[i].X = start_block.X;
        this->blocks[i].Y = start_block.Y + i;
    }
    }

public:
    bool isRotatable(ROTATE_DIR rdir) { return false; };
    void Rotate(ROTATE_DIR rdir) { return; };

    void Draw(void); // {     }
};

/*
LineShape::LineShape(Table *tbl, BLOCK start_block) : Shape(tbl)
{

}

*/
void LineShape::Draw(void)
{
for (int i = 0; i < 4; i++)
        {
            DrawSingleBlock(blocks[i]);
        }
}

Open in new window





||=== Build: Debug in Tetris (compiler: GNU GCC Compiler) ===|
obj\Debug\Table.o||In function `ZN9LineShape4DrawEv':|
C:\codeblocks\Tetris\Table.h|128|multiple definition of `LineShape::Draw()'|
obj\Debug\main.o:C:\codeblocks\Tetris\table.h|128|first defined here|
||=== Build failed: 2 error(s), 0 warning(s) (0 minute(s), 1 second(s)) ===|


Where is that "multiple" definition?
0
Comment
Question by:Nusrat Nuriyev
  • 4
  • 2
  • 2
8 Comments
 
LVL 16

Expert Comment

by:HooKooDooKu
ID: 40488794
The parent class 'Shape' has a Draw function that is declared as virtual.
The child class 'LineShape' has a Draw function this is not declared as virtual.  
Since LineShape inherited the virtual Draw of Shape, you have two different definitions of Draw in LineShape.

Simply add the virtual key word to your Draw function in LineShape.  That way, the Draw function in LineShape will "over-ride" the Draw function it inherited from Shape.
0
 

Author Comment

by:Nusrat Nuriyev
ID: 40489067
nope


class Shape
{

public:
    BLOCK blocks[4];
    SHAPE_TYPE whoami;
    friend Table;
    Table *tbl;
    // Default constructor
    Shape() {};
    //Shape(Table *tbl) { this->tbl = tbl;}
public:
    // non-virtual
    void DrawSingleBlock(BLOCK block)
    {
        RECT rect;
        HBRUSH brush = CreateSolidBrush(RGB(0, 255, 0));

        rect.top    = (*tbl).initial_point.y + block.Y * (*tbl).cell.height;
        rect.left   = (*tbl).initial_point.x + block.X * (*tbl).cell.width;
        rect.bottom = rect.top + tbl->cell.height;
        rect.right  = rect.left + tbl->cell.width;

        FillRect(tbl->hdc, &rect, brush);
    }

    // virtual
    virtual void Draw(void) {};
    virtual void Rotate(ROTATE_DIR rdir){ return; };
    virtual bool isRotatable(ROTATE_DIR rdir){ return false;};
};

class LineShape : public Shape
{
public:
    LineShape();
    LineShape(Table *tbl, BLOCK start_block)
    {
        this->tbl = tbl;
    for (int i = 0; i < 4; i++)
    {
        this->blocks[i].X = start_block.X;
        this->blocks[i].Y = start_block.Y + i;
    }
    }

public:
    bool isRotatable(ROTATE_DIR rdir) { return false; };
    void Rotate(ROTATE_DIR rdir) { return; };

    virtual void Draw(void); // {     }
};

/*
LineShape::LineShape(Table *tbl, BLOCK start_block) : Shape(tbl)
{

}

*/
void LineShape::Draw(void)
{
    for (int i = 0; i < 4; i++)
            {
                DrawSingleBlock(blocks[i]);
            }
}

Open in new window


this does not work.
0
 

Author Comment

by:Nusrat Nuriyev
ID: 40489074
However,

class Shape
{

public:
    BLOCK blocks[4];
    SHAPE_TYPE whoami;
    friend Table;
    Table *tbl;
    // Default constructor
    Shape() {};
    //Shape(Table *tbl) { this->tbl = tbl;}
public:
    // non-virtual
    void DrawSingleBlock(BLOCK block)
    {
        RECT rect;
        HBRUSH brush = CreateSolidBrush(RGB(0, 255, 0));

        rect.top    = (*tbl).initial_point.y + block.Y * (*tbl).cell.height;
        rect.left   = (*tbl).initial_point.x + block.X * (*tbl).cell.width;
        rect.bottom = rect.top + tbl->cell.height;
        rect.right  = rect.left + tbl->cell.width;

        FillRect(tbl->hdc, &rect, brush);
    }

    // virtual
    virtual void Draw(void) {};
    virtual void Rotate(ROTATE_DIR rdir){ return; };
    virtual bool isRotatable(ROTATE_DIR rdir){ return false;};
};

class LineShape : public Shape
{
public:
    LineShape();
    LineShape(Table *tbl, BLOCK start_block)
    {
        this->tbl = tbl;
    for (int i = 0; i < 4; i++)
    {
        this->blocks[i].X = start_block.X;
        this->blocks[i].Y = start_block.Y + i;
    }
    }

public:
    bool isRotatable(ROTATE_DIR rdir) { return false; };
    void Rotate(ROTATE_DIR rdir) { return; };

    virtual void Draw(void)  {   for (int i = 0; i < 4; i++)
            {
                DrawSingleBlock(blocks[i]);
            } }
};

Open in new window


this does work.

Again, what is the problem?
0
 
LVL 16

Expert Comment

by:HooKooDooKu
ID: 40489175
It works for me.

The following code was compiled using Microsoft Visual Stdio 2010.  I created a new project.  I added a file "Shape.cpp" to the project, and inserted the following code (note the dummy classes I had to create to account for the "missing" source code your sample didn't include).
#include "stdafx.h"

class BLOCK
{
public:
	int X;
	int Y;
};

class Cell
{
public:
	int height;
	int width;
};

#define SHAPE_TYPE int
#define ROTATE_DIR int

class Table
{
public:
	Table(){};
	POINT initial_point;
	Cell cell;
	HDC hdc;
};

class Shape
{
public:
    BLOCK blocks[4];
    SHAPE_TYPE whoami;
    friend Table;
    Table *tbl;
    // Default constructor
    Shape() {};
    //Shape(Table *tbl) { this->tbl = tbl;}
public:
    // non-virtual
    void DrawSingleBlock(BLOCK block)
    {
        RECT rect;
        HBRUSH brush = CreateSolidBrush(RGB(0, 255, 0));

        rect.top    = (*tbl).initial_point.y + block.Y * (*tbl).cell.height;
        rect.left   = (*tbl).initial_point.x + block.X * (*tbl).cell.width;
        rect.bottom = rect.top + tbl->cell.height;
        rect.right  = rect.left + tbl->cell.width;

        FillRect(tbl->hdc, &rect, brush);
    }

    // virtual
    virtual void Draw(void) {};
    virtual void Rotate(ROTATE_DIR rdir){ return; };
    virtual bool isRotatable(ROTATE_DIR rdir){ return false;};
};

class LineShape : public Shape
{
public:
    LineShape();
    LineShape(Table *tbl, BLOCK start_block)
    {
        this->tbl = tbl;
    for (int i = 0; i < 4; i++)
    {
        this->blocks[i].X = start_block.X;
        this->blocks[i].Y = start_block.Y + i;
    }
    }

public:
    bool isRotatable(ROTATE_DIR rdir) { return false; };
    void Rotate(ROTATE_DIR rdir) { return; };

    virtual void Draw(void); // {     }
};

/*
LineShape::LineShape(Table *tbl, BLOCK start_block) : Shape(tbl)
{

}

*/
void LineShape::Draw(void)
{
    for (int i = 0; i < 4; i++)
            {
                DrawSingleBlock(blocks[i]);
            }
}

Open in new window


Logically, your latest two samples are the same.  The only difference is the 2nd didn't define the Draw() function 'in-line'.  But that shouldn't matter.
0
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 
LVL 32

Accepted Solution

by:
sarabande earned 500 total points
ID: 40489251
if you put the implementation of a non-template function into a header file, and don't make it inline, the compiler would generate a copy of the function for each cpp file where you included the header file and put the compiled code to the object file (*.o) which was the output (file) of the compilation.

the linker than complains a duplicate implementation when it tries to bind both object files to one executable.

to solve the issue, you have a few choices:

(1) move the implementation of LineShape::Draw to a new cpp file
     and add the cpp to project file or makefile.
(2) implement the function directly in the class definition (what makes it inline)
(3) declare the function as inline in the class
(4) make the class a template class. then the compiler will compile the
     functions inline when they were used rather than when the header was compiled.

Sara
0
 

Author Comment

by:Nusrat Nuriyev
ID: 40489586
or.
(5) declare the function as inline in header file but not in the class.

I have used  (1).
About (5).
Are the all function  inline in template class?
0
 
LVL 32

Expert Comment

by:sarabande
ID: 40490756
no, the functions are not really 'inline' but the compilation of the function happens in the calling function when a concrete template type was known and the template was instantiated with that type.

for example if you have class MyContainer<T> with member function 'void insert(const T & t)', the MyContainer<short::insert(const short & t)  was compiled if you do like

...
MyContainer<short> mys;  // here the class was instantiated
mys.insert(-1);                       // here the insert function was compiled (if 1st call)

Open in new window


but, different to an inline function, the compiler doesn't embed the code into the calling function but adds a new function and a call. if the same function was called again, it uses the same function module (while an inline function would be embedded again)  

(5) declare the function as inline in header file but not in the class.
where do you see a difference to (3) ?

Sara
0
 

Author Comment

by:Nusrat Nuriyev
ID: 40492267
Thanks,
where do you see a difference to (3) ?
Nowhere, it was an illusion.
0

Featured Post

Enabling OSINT in Activity Based Intelligence

Activity based intelligence (ABI) requires access to all available sources of data. Recorded Future allows analysts to observe structured data on the open, deep, and dark web.

Join & Write a Comment

Suggested Solutions

Introduction This article is the first in a series of articles about the C/C++ Visual Studio Express debugger.  It provides a quick start guide in using the debugger. Part 2 focuses on additional topics in breakpoints.  Lastly, Part 3 focuses on th…
Container Orchestration platforms empower organizations to scale their apps at an exceptional rate. This is the reason numerous innovation-driven companies are moving apps to an appropriated datacenter wide platform that empowers them to scale at a …
The goal of the video will be to teach the user the concept of local variables and scope. An example of a locally defined variable will be given as well as an explanation of what scope is in C++. The local variable and concept of scope will be relat…
The viewer will learn how to clear a vector as well as how to detect empty vectors in C++.

743 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

10 Experts available now in Live!

Get 1:1 Help Now