简体   繁体   中英

C++ multiple definition of method error; learning Inheritance

Hi everyone this is my first post on stack. am learning C++ from a book "C++ programming for the absolute beginner" by Mark Lee. I am currently learning inheritance by making a game about dragons. I know that its in good practice to make a header file for definitions and a cpp file for implementation. However, I followed what the guy wrote in the book and both defined and wrote the implementation in the same file .cpp (which i believe is still allowed in c++ correct?). Anyway after finishing it and trying to compile I get

Multiple definition of Dragon::attack(int)

And this error appears for just about all the methods. There are no linker errors that pop up. Sorry if my explanation went on to long. here are the files. Thank you in advance and if it is at all possible can I keep the classes the way they are both definition and implementation in the same file.

Dragon.cpp

#pragma once
#include<string>
#include<ctime>
#include<cstdlib>

using std::string;
#define MAX(a,b) a>b? a:b

class Dragon
{
      private:
              int speed;
              string name;
              int hitPoints;
              int armor;
              int treasure;
              int clawDamage;
              int size;
      protected:
                Dragon(int theSize);
                int getArmor(){return armor;}
                 int& getHitPoints(){return hitPoints;}
                int getClawDamage(){return clawDamage;}
               int getSize() {return size;}
                virtual int attack(int targetArmor, int specialDamage);
     public:
            virtual int attack(int targetArmor)=0;
            virtual void defend(int damage)=0;
     int getTreasure(){return treasure;}
           virtual string getName(){return name;}
             int getSpeed(){return speed;}
           bool isAlive(){return hitPoints>0;}
};

 Dragon::Dragon(int theSize): size(theSize)
{
          if (size<1||size >4)
            size=3;
     clawDamage=2*size;
     speed=2*size;
     hitPoints=4*size;
     armor=size;
     treasure=1000*size;
     srand(time(0));
}
 int Dragon::attack(int targetArmor, int specialDamage)
{
        int useSpecial=rand()%2; //0 or 1
        int damage;
        if(useSpecial)
        damage=specialDamage;
         else 
         damage=getClawDamage();
         return MAX(damage-targetArmor,0);
}      

BlackDragon.cpp

#include<string>
#include"Dragon.cpp"

using std::string;

class BlackDragon : public Dragon
{
      private:
              int poisonDamage;
      public:
             BlackDragon(int theSize);
             int attack(int targetArmor);
             void defend(int damage);
             string getName(){return "Black Dragon";}
};

BlackDragon::BlackDragon(int theSize):Dragon(theSize)
{
     poisonDamage=getSize();
}
int BlackDragon::attack(int targetArmor)
{
    return Dragon::attack(targetArmor, poisonDamage);
}
void BlackDragon::defend(int damage)
{
    getHitPoints()-=damage - getArmor();
}

RedDragon.cpp

#include<string>
#include"Dragon.cpp"

using std::string;

class RedDragon : public Dragon
 {
      private:
              int fireDamage;
      public:
             RedDragon(int theSize);
             int attack(int targetArmor);
             void defend(int damage);
             string getName(){return "Red Dragon";}
};
RedDragon::RedDragon(int theSize):Dragon(theSize)
{
            fireDamage=4*getSize();
}
int RedDragon::attack(int targetArmor)
{
    return Dragon::attack(targetArmor, fireDamage);
}
void RedDragon::defend(int damage)
{
     getHitPoints()-=(damage-getArmor())/3;
}

BlueDragon.cpp

#include<string>
#include"Dragon.cpp"

using std::string;

class BlueDragon: public Dragon
{
      private:
              int iceDamage;
      public:
             BlueDragon(int theSize);
             int attack(int targetArmor);
             void defend(int damage);
             string getName(){return "Blue Dragon";}
};
BlueDragon::BlueDragon(int theSize):Dragon(theSize)
{
            iceDamage=3*getSize();
}

int BlueDragon::attack(int targetArmor)
{
    return Dragon::attack(targetArmor, iceDamage);
}
void BlueDragon::defend(int damage)
{
     getHitPoints()-=(damage-getArmor())/2;
}

DragonLord.cpp

#include<iostream>
#include<ctime>
#include<cstdlib>
#include "Dragon.cpp"
#include "RedDragon.cpp"
#include "BlueDragon.cpp"
#include "BlackDragon.cpp"

int menuChoice();

int main(void)
{
    using std::srand;
    using std::time;
    using std::rand;
    using std::cout;
    srand((unsigned int)time(0));
    Dragon* dragons[3];
    int hp=15;
    int armor=2;
    int tempArmor;
    int tempAttack;
    dragons[0]=new RedDragon(rand()%4+1);
    dragons[1]=new BlackDragon(rand()%4+1);
    dragons[2]=new BlueDragon(rand()%4+1);
    Dragon* d=dragons[rand()%3];
    cout<<"Welcome noble knight. \n"
    <<"You must save a princess."
    <<"She has been captured by a "
    <<d->getName()<<"\n"
    <<"You must defeat the dragon. \n";
    cout<<"Your hit points are: "<<hp<<"\n";
   while(d->isAlive()&&hp>0)
    {
        int choice=menuChoice();
    if(choice==3)
         goto RUN;
      else if(choice==1)
      {
           tempAttack=rand()%16+5;
           tempArmor=armor;
      }
      else
      {
          tempAttack=rand()%11;
          tempArmor=armor+4;
      }
      hp-=d->attack(armor);
      d->defend(rand()%16-5);
      cout<<"\nYou deliver a mighty blow and deel "<<tempAttack
      <<" damage. \n";
      cout<<"Your hit points are: "<<hp;
      }
      if(d->isAlive())
      cout<<"\nYou have perished before"
      <<" the might of the dragon.\n";
      else 
      cout<<"\n\nYou ahve slain the dragon!"
      <<"Congratulations.\n"
      <<"the Princess is saved. \n";
      return 0;
      RUN:
          cout<<"\nYou ahve fled in cowardice.\n";
          return 0;
}

int menuChoice()
{
    using std::cout;
    using std::cin;
    int choice;
    do{
        cout<<"\n[1]Atack\n"
        <<"[2]Defensive Mode\n"
        <<"[3]Run Away\n";
        cin>>choice;
      }while(choice<1&& choice>3);
      return choice;
}

You are defining your classes in .cpp files and including them multiple times. For example, when you include Dragon.cpp in both BlackDragon.cpp and BlackDragon.cpp , there will be two definition of everything in Dragon class. That will cause this problem (breaks One Definition Rule ).

There are ways to avoid this, but in C++ most common and easy practice is to declare your class in header (.h) files and implement the methods in .cpp files. If one class definition is needed in another, then include the .h file.

You can do like this:

//Dragon.h
class Dragon
{
  private:
          int speed;
          string name;
          int hitPoints;
          int armor;
  /// other variables and methods
}

//Dragon.cpp
 #include"Dragon.h"


//implement methods

then in inheriting classes

//BlueDragon.h
 #include"Dragon.h"

 //BlueDragon Class definition

//BlueDragon.cpp
#include "BlueDragon.h"
//BlueDragon methods implementation

You are including ".cpp" files. It's a very bad idea. In practice, you should define your classes in header files and implement them in cpp files. That way, you don't expose your implementation, only your interface, and each symbol will be compiled one and only one time. That should solve your problem.

Also, there are case when you may want to implement methods in header files, like when creating a template class, but you should never include anything that's not a header.

Your book seems a bit outdated, using a macro instead of std::max and such. You should probably grab a new, shiny book about C++11 instead.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM