__此调用已在.obj中定义
__thiscall already defined in .obj
我收到了链接器错误,在检查是否包含.cpp文件和阅读其他论坛后,我似乎找不到根本原因。
错误为:
1>------ Build started: Project: Penguin_RPG, Configuration: Debug Win32 ------
1> main.cpp
1>c:usersadamdocumentsvisual studio 2013projectspenguin_rpgpenguin_rpgdialogue.hpp(53): warning C4018: '<=' : signed/unsigned mismatch
1>c:usersadamdocumentsvisual studio 2013projectspenguin_rpgpenguin_rpgmain.cpp(39): warning C4244: 'argument' : conversion from 'time_t' to 'unsigned int', possible loss of data
1>main.obj : error LNK2005: "public: __thiscall Area::Area(class Dialogue,class Inventory,class std::vector<class Creature *,class std::allocator<class Creature *> >)" (??0Area@@QAE@VDialogue@@VInventory@@V?$vector@PAVCreature@@V?$allocator@PAVCreature@@@std@@@std@@@Z) already defined in atlas.obj
1>main.obj : error LNK2005: "public: __thiscall Creature::Creature(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,int,int,int,int,double,unsigned int,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >)" (??0Creature@@QAE@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@HHHHNI0@Z) already defined in atlas.obj
1>main.obj : error LNK2005: "public: __thiscall Creature::Creature(void)" (??0Creature@@QAE@XZ) already defined in atlas.obj
1>main.obj : error LNK2005: "public: __thiscall Dialogue::Dialogue(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,class std::vector<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,class std::allocator<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > > >)" (??0Dialogue@@QAE@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@V?$vector@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@2@@2@@Z) already defined in atlas.obj
1>main.obj : error LNK2005: "public: __thiscall Item::Item(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >)" (??0Item@@QAE@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@0@Z) already defined in atlas.obj
1>main.obj : error LNK2005: "public: __thiscall Weapon::Weapon(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,unsigned int,double)" (??0Weapon@@QAE@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@0IN@Z) already defined in atlas.obj
1>main.obj : error LNK2005: "public: int __thiscall Dialogue::activate(void)" (?activate@Dialogue@@QAEHXZ) already defined in atlas.obj
1>main.obj : error LNK2005: "public: void __thiscall Inventory::add_armour(class Armour *,int)" (?add_armour@Inventory@@QAEXPAVArmour@@H@Z) already defined in atlas.obj
1>main.obj : error LNK2005: "public: void __thiscall Inventory::add_item(class Item *,int)" (?add_item@Inventory@@QAEXPAVItem@@H@Z) already defined in atlas.obj
1>main.obj : error LNK2005: "public: void __thiscall Inventory::add_weapon(class Weapon *,int)" (?add_weapon@Inventory@@QAEXPAVWeapon@@H@Z) already defined in atlas.obj
1>main.obj : error LNK2005: "public: void __thiscall Inventory::clear(void)" (?clear@Inventory@@QAEXXZ) already defined in atlas.obj
1>main.obj : error LNK2005: "public: void __thiscall Creature::equipArmour(class Armour *)" (?equipArmour@Creature@@QAEXPAVArmour@@@Z) already defined in atlas.obj
1>main.obj : error LNK2005: "public: void __thiscall Creature::equipWeapon(class Weapon *)" (?equipWeapon@Creature@@QAEXPAVWeapon@@@Z) already defined in atlas.obj
1>main.obj : error LNK2005: "public: unsigned int __thiscall Creature::expToLevel(unsigned int)" (?expToLevel@Creature@@QAEII@Z) already defined in atlas.obj
1>main.obj : error LNK2005: "public: bool __thiscall Creature::levelUp(void)" (?levelUp@Creature@@QAE_NXZ) already defined in atlas.obj
1>main.obj : error LNK2005: "public: void __thiscall Inventory::merge(class Inventory *)" (?merge@Inventory@@QAEXPAV1@@Z) already defined in atlas.obj
1>main.obj : error LNK2005: "public: void __thiscall Inventory::print(bool)" (?print@Inventory@@QAEX_N@Z) already defined in atlas.obj
1>main.obj : error LNK2005: "public: int __thiscall Inventory::print_armours(bool)" (?print_armours@Inventory@@QAEH_N@Z) already defined in atlas.obj
1>main.obj : error LNK2005: "public: int __thiscall Inventory::print_items(bool)" (?print_items@Inventory@@QAEH_N@Z) already defined in atlas.obj
1>main.obj : error LNK2005: "public: int __thiscall Inventory::print_weapons(bool)" (?print_weapons@Inventory@@QAEH_N@Z) already defined in atlas.obj
1>main.obj : error LNK2005: "public: void __thiscall Inventory::remove_armour(class Armour *,int)" (?remove_armour@Inventory@@QAEXPAVArmour@@H@Z) already defined in atlas.obj
1>main.obj : error LNK2005: "public: void __thiscall Inventory::remove_item(class Item *,int)" (?remove_item@Inventory@@QAEXPAVItem@@H@Z) already defined in atlas.obj
1>main.obj : error LNK2005: "public: void __thiscall Inventory::remove_weapon(class Weapon *,int)" (?remove_weapon@Inventory@@QAEXPAVWeapon@@H@Z) already defined in atlas.obj
1>main.obj : error LNK2005: "public: void __thiscall Area::search(class Creature &)" (?search@Area@@QAEXAAVCreature@@@Z) already defined in atlas.obj
1>C:UsersAdamDocumentsVisual Studio 2013ProjectsPenguin_RPGDebugPenguin_RPG.exe : fatal error LNK1169: one or more multiply defined symbols found
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
atlas.hpp:
#pragma once
#ifndef ATLAS_HPP
#define ATLAS_HPP
#include <vector>
#include "creature.hpp"
#include "item.hpp"
#include "weapon.hpp"
#include "armour.hpp"
#include "area.hpp"
//atlas building functions. Atlases contain vectors of
//game data that is not modified. Could be replaced with
//functions that read from config files.
void buildatlas_creature(std::vector<Creature>& atlas);
void buildatlas_item(std::vector<Item>& atlas);
void buildatlas_weapon(std::vector<Weapon>& atlas);
void buildatlas_armours(std::vector<Armour>& atlas);
void buildatlas_area(std::vector<Area>& atlas,
std::vector<Item>& items, std::vector<Weapon>& weapons,
std::vector<Armour>& armours, std::vector<Creature>& creatures);
#endif //ATLAS_HPP
atlas.cpp:
#include "atlas.hpp"
void buildatlas_creature(std::vector<Creature>& atlas)
{
//fill the atlas
//Creature(name, health, str, end, dex, hitRate, level)
atlas.push_back(Creature("Rat", 8, 8, 8, 12, 2.0, 1));
return;
}
void buildatlas_item(std::vector<Item>& atlas)
{
//Item(name, description)
atlas.push_back(Item("Gold Coin",
"A small disc made of lustrous metal"));
atlas.push_back(Item("Iron Key",
"A heavy iron key with a simple cut"));
return;
}
void buildatlas_weapon(std::vector<Weapon>& atlas)
{
//Weapon(name, description, damage, hitRate)
atlas.push_back(Weapon("Iron Dagger",
"A short blade made of iron with a leather hilt",
5, 10.0));
atlas.push_back(Weapon("Excalibur",
"The legendary blade, bestowed upon you by the lady of the lake",
35, 35.0));
return;
}
void buildatlas_armours(std::vector<Armour>& atlas)
{
//Armour(name, description, defence, slot)
atlas.push_back(Armour("Leather Vest",
"Torso armour made of tanned hide",
4, Armour::Slot::TORSO));
return;
}
void buildatlas_area(std::vector<Area>& atlas,
std::vector<Item>& items, std::vector<Weapon>& weapons,
std::vector<Armour>& armours, std::vector<Creature>& creatures)
{
// Area definitions are somewhat more complicated:
atlas.push_back(Area(Dialogue( // Standard dialogue definiton
"You are in room 1", // Description
{ "Go to room 2", "Search" }), // Choices
Inventory( // Area inventory
{
std::make_pair(&items[0], 5) // Pair of item and quantity
},
{
std::make_pair(&weapons[0], 1)// Pair of weapon and quantity
},
{
std::make_pair(&armours[0], 1) // Pair of armour and quantity
}),
{ // Creatures
}));
atlas.push_back(Area(Dialogue(
"You are in room 2",
{ "Go to room 1", "Search" }),
Inventory(
{
std::make_pair(&items[0], 10),
std::make_pair(&items[1], 1)
},
{
},
{
}),
{
&creatures[0]
}));
return;
}
inventory.hpp:
#pragma once
#ifndef INVENTORY_HPP
#define INVENTORY_HPP
#include "item.hpp"
#include "weapon.hpp"
#include "armour.hpp"
#include <list>
#include <utility>
#include <iostream>
class Inventory
{
public:
//Whilst weapons and armour are items, they have their own
//specific properties and can't be stored in the same list.
//The first element of the pair stores a pointer to the item
//in the item/weapon/armour atlas, defined in main(), the second
//if the quantity of the item
std::list<std::pair<Item*, int>> items;
std::list<std::pair<Weapon*, int>> weapons;
std::list<std::pair<Armour*, int>> armours;
Inventory(){};
Inventory(std::list<std::pair<Item*, int>> items,
std::list<std::pair<Weapon*, int>> weapons,
std::list<std::pair<Armour*, int>> armours)
{
this->items = items;
this->weapons = weapons;
this->armours = armours;
}
void add_item(Item* item, int count);
void add_weapon(Weapon* weapon, int count);
void add_armour(Armour* armour, int count);
void remove_item(Item*, int count);
void remove_weapon(Weapon*, int count);
void remove_armour(Armour*, int count);
void merge(Inventory* inventory);
void clear();
int print_items(bool label);
int print_weapons(bool label);
int print_armours(bool label);
void print(bool label);
};
//add an item to the inventory
void Inventory::add_item(Item* item, int count)
{
// Increase the quantity if the item already exists
for (auto& it : this->items)
{
if (it.first == item) it.second += count;
return;
}
// If the item doesn't already exist in the inventory, then a
// pair must be created too
this->items.push_back(std::make_pair(item, count));
}
void Inventory::add_weapon(Weapon* weapon, int count)
{
for (auto& it : this->weapons)
{
if (it.first == weapon)
{
it.second += count;
return;
}
}
this->weapons.push_back(std::make_pair(weapon, count));
}
void Inventory::add_armour(Armour* armour, int count)
{
for (auto& it : this->armours)
{
if (it.first == armour)
{
it.second += count;
return;
}
}
this->armours.push_back(std::make_pair(armour, count));
}
void Inventory::remove_item(Item* item, int count)
{
// Iterate through the items, and if they are found then decrease
// the quantity by the quantity removed
for (auto& it : this->items)
{
if (it.first == item) it.second -= count;
}
// Iterate through the list again, and remove any elements from
// the list that have zero or less for their quantity
// We do this in two passes because removing an element from
// a list during a for loop invalidates the iterators, and the
// loop stops working
this->items.remove_if([](std::pair<Item*, int>& element)
{
return element.second < 1;
});
}
void Inventory::remove_weapon(Weapon* weapon, int count)
{
for (auto& it : this->weapons)
{
if (it.first == weapon) it.second -= count;
}
this->weapons.remove_if([](std::pair<Weapon*, int>& element)
{
return element.second < 1;
});
}
void Inventory::remove_armour(Armour* armour, int count)
{
for (auto& it : this->armours)
{
if (it.first == armour) it.second -= count;
}
this->armours.remove_if([](std::pair<Armour*, int>& element)
{
return element.second < 1;
});
}
//merge the specified Inventory with the current one
//adding item quantaties if they exist, creating a new slot if they don't
void Inventory::merge(Inventory* inventory)
{
// You can't merge an inventory with itself!
if (inventory == this) return;
// Loop through the items to be added, and add them. Our addition
// function will take care of everything else for us
for (auto it : inventory->items)
{
this->add_item(it.first, it.second);
}
// Do the same for the weapons
for (auto it : inventory->weapons)
{
this->add_weapon(it.first, it.second);
}
// Do the same for the armour
for (auto it : inventory->armours)
{
this->add_armour(it.first, it.second);
}
return;
}
void Inventory::clear()
{
this->items.clear();
this->weapons.clear();
this->armours.clear();
}
//output a list of items to stdout, nicely formatted
int Inventory::print_items(bool label = false)
{
unsigned int i = 1;
for(std::list<std::pair<Item*, int>>::iterator it =
this->items.begin(); it != this->items.end(); ++it)
{
//number items if asked
if(label)
{
std::cout << i++ << ":";
//output the item name, quantity and description
std::cout << it->first->name << " (" << it->second << ") - ";
std::cout <<it->first->description << std::endl;
}
}
//return number of items outputted, for convienience
return this->items.size();
}
//output a list of weapons to stdout, nicely formatted
int Inventory::print_weapons(bool label = false)
{
unsigned int i = 1;
for (auto it : this->weapons)
{
if (label) std::cout << i++ << ": ";
std::cout << it.first->name << " (" << it.second << ") - ";
std::cout << it.first->description << std::endl;
}
return this->weapons.size();
}
//output a list of armour to stdout, nicely formatted
int Inventory::print_armours(bool label = false)
{
unsigned int i = 1;
for(std::list<std::pair<Armour*, int>>::iterator it =
this->armours.begin(); it != this->armours.end(); ++it)
{
//number items if asked
if(label)
{
std::cout << i++ << ":";
//output the item name, quantity and description
std::cout << it->first->name << " (" << it->second << ") - ";
std::cout <<it->first->description << std::endl;
}
}
//return number of items outputted, for convienience
return this->armours.size();
}
//print the entire inventory, unless it is empty
void Inventory::print(bool label = false)
{
if(this->items.size() == 0 &&
this->weapons.size() == 0 &&
this->armours.size() == 0)
{
std::cout << "Empty!" << std::endl;
}
else
{
this->print_items(label);
this->print_weapons(label);
this->print_armours(label);
}
return;
}
#endif //INVENTORY_HPP
main.cpp:
#include <iostream>
#include <string>
#include <vector>
#include <list>
#include <utility>
#include <cstdlib>
#include <ctime>
#include "area.hpp"
#include "armour.hpp"
#include "atlas.hpp"
#include "creature.hpp"
#include "dialogue.hpp"
#include "inventory.hpp"
#include "item.hpp"
#include "weapon.hpp"
Creature dialogue_newChar();
int main(void)
{
std::vector<Creature> creatureAtlas;
std::vector<Item> itemAtlas;
std::vector<Weapon> weaponAtlas;
std::vector<Armour> armourAtlas;
std::vector<Area> areaAtlas;
// Build the atlases
buildatlas_creature(creatureAtlas);
buildatlas_item(itemAtlas);
buildatlas_weapon(weaponAtlas);
buildatlas_armours(armourAtlas);
buildatlas_area(areaAtlas, itemAtlas, weaponAtlas,
armourAtlas, creatureAtlas);
Creature player;
//seed rand() with system time, to produce better random numbers
srand(time(NULL));
//main game menu dialogue
int result = Dialogue("Welcome to the jungle!", { "New Game" }).activate();
switch (result)
{
case 1:
player = dialogue_newChar();
break;
default:
return 0;
break;
}
// Set the current area to be the first area in the atlas,
// essentially placing the player there upon game start
Area* currentArea = &(areaAtlas[0]);
// Play the game until a function breaks the loop and closes it
while (1)
{
// If the player has died then inform them as such and close
// the program
if (player.health <= 0)
{
std::cout << "t----YOU DIED----n Game Overn";
return 0;
}
// Activate the current area's dialogue
result = currentArea->dialogue.activate();
// These could be moved inside of the area code using an
// event style system, but that allows for much less
// flexibility with what happens in each area. Since we're
// defining the areas in code anyway, sticking with this
// isn't too much of a problem, and it keeps things easy
// to understand
if (currentArea == &(areaAtlas[0]))
{
switch (result)
{
case 1:
// Move to area 1
currentArea = &(areaAtlas[1]);
break;
case 2:
// Search the area
currentArea->search(player);
break;
default:
break;
}
}
else if (currentArea == &(areaAtlas[1]))
{
switch (result)
{
// Move to area 0
case 1:
currentArea = &(areaAtlas[0]);
break;
// Search the area
case 2:
currentArea->search(player);
break;
default:
break;
}
}
}
return 0;
}
//create a new character
Creature dialogue_newChar()
{
//ask for a name and class
std::cout << "Choose your name punk!" << std::endl;
std::string name;
std::cin >> name;
int result = Dialogue("Choose your class!", { "Fighter", "Rogue" }).activate();
switch (result)
{
case 1:
//Fighter favours health and strength
return Creature(name, 35, 20, 10, 5, 10.0, 1, "Fighter");
break;
case 2:
//Rogue favours endurance and dexterity
return Creature(name, 30, 5, 10, 20, 15.0, 1, "Rogue");
break;
default:
//default should not happen, good to be safe though!
return Creature(name, 30, 10, 10, 10, 10.0, 1, "Adventurer");
break;
}
}
如果需要,我可以添加其他文件的代码。谢谢
定义成员函数时,可以选择以下选项来防止多重定义:
-
把它们放在
.cpp
文件中,而不是像现在这样放在.hpp
文件中。这是最可取的。 -
将它们内联在类主体中。在某些情况下,适用于一句俏皮话。
-
将它们放在类主体之外,但用
inline
关键字标记它们。
现在,您已经在头文件中的类主体之外定义了成员函数,并且没有用inline
标记。我建议您执行#1,并将它们移到.cpp
文件中。
您需要将Inventory类方法的实现移动到.cpp文件中。
现在的情况是,头文件包含在几个不同的.cpp文件中,所以这两个方法是以几个不同的编译单元编译的。这导致了链接错误,即那些metid已经存在于不同的编译单元中。
事实上,除了模板实现之外的所有实现都应该存在于它们自己的.cpp文件中,正是出于这个原因。
当您尝试将具有类Inventory
方法实现的单个inventory.hpp
文件包含到不同的.cpp
(通过atlas.hpp
实现的main.cpp
和atlas.cpp
(文件时,会出现此问题。如果您将Inventory
类的接口和实现分离,那么它将解决您的问题。
分离也很重要,因为
- 您隐藏了实现,因此客户端代码必须通过对象的公共接口使用对象
- 它减少了项目的构建时间
- 您可以在不更改接口文件
.hpp
的情况下更改实现.cpp
文件
关于分离的更多信息,您可以阅读文章《C++中的分离接口和实现》
我也遇到了类似的问题。然后我意识到我在单独的.cpp文件中对.h文件有多个声明。这解决了问题。
#include "*.hpp"
将多次定义您的方法。制作一个*.h
文件,在那里声明所有方法并使用
#include "*.h"
在*.cpp
文件中定义方法。
- float* 已在 Gameobject.obj 中定义
- 为什么定义复制构造函数会给我错误:无法将类型 'obj&' 的非常量左值引用绑定到类型为"obj"的右值?
- C++ LNK 2005 错误"已在 .obj 中定义
- "... already defined in *.obj"但我没有在同一范围内两次定义任何变量
- 已经在 .obj 中定义,即使有 #ifndef #define #endif
- 需要的具体示例.错误:已经定义的.OBJ 一个或多个多个定义的符号
- Main.Obj中已经定义的主要
- 变量已在 .obj 中定义;这是怎么回事?
- 已在 ConsoleApplication1.obj 中定义
- DllMain 已在 dllmain.obj 中定义
- 已在main.obj中定义了双精度
- 错误LNK2005结构已在.obj文件中定义
- 已经在main.obj中定义了
- 变量已在 .obj 中定义,但没有循环包含
- 成员函数已在.obj(visual studio)中定义
- 链接器错误: /* 项实例 */ 已在项.obj 中定义
- 错误 11 错误 LNK2005:已在 MyForm.obj 中定义"class cv::Mat imageOutput" (?imageOutput@@3VMat@cv@@A)
- 错误 LNK2005:"class Player m_player"已在 Game.obj 中定义
- 已经定义了 Obj?链接错误
- LNK2005错误,已在main.obj中定义