简体   繁体   English

C ++方法错误的多重定义; 学习继承

[英]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. 我从Mark Lee的著作《面向绝对初学者的C ++编程》中学习了C ++。 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. 我知道,按照惯例,可以创建用于定义的头文件和用于实现的cpp文件。 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?). 但是,我遵循那家伙在书中写的内容,并在同一文件.cpp中定义和编写了实现(我相信在c ++中还是允许的吗?)。 Anyway after finishing it and trying to compile I get 无论如何,完成并尝试编译后,我得到了

Multiple definition of Dragon::attack(int) 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 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 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 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 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 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. 您正在.cpp文件中定义类,并多次包含它们。 For example, when you include Dragon.cpp in both BlackDragon.cpp and BlackDragon.cpp , there will be two definition of everything in Dragon class. 例如,当你包括Dragon.cpp两个BlackDragon.cppBlackDragon.cpp,会有一切两个定义Dragon类。 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. 有很多方法可以避免这种情况,但是在C ++中,最常见且最简单的做法是在标头(.h)文件中声明您的类,并在.cpp文件中实现这些方法。 If one class definition is needed in another, then include the .h file. 如果在另一个类中需要一个类定义,则包括.h文件。

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. 您包括“ .cpp”文件。 It's a very bad idea. 这是一个非常糟糕的主意。 In practice, you should define your classes in header files and implement them in cpp files. 实际上,您应该在头文件中定义类,并在cpp文件中实现它们。 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. 您的书似乎有点过时了,使用宏而不是std :: max等。 You should probably grab a new, shiny book about C++11 instead. 您可能应该改而读一本关于C ++ 11的新书。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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