Я полностью в остроумии: я не могу понять, как мои проблемы зависимости. Я прочитал множество постов и блогов и переделывал свой код так много раз, что даже не помню, что почти сработало, а что нет. Я постоянно получаю не только ошибки переопределения, но и ошибки класса не определены. Я переделываю защиту заголовков и удаляю некоторые ошибки, просто чтобы найти другие. Я как-то все сводил к одной ошибке, но потом даже это сломалось, когда я пытался это исправить.
Не могли бы вы помочь мне разобраться в проблеме?
card.cpp
#include <iostream>
#include <cctype>
#include "card.h"
using namespace std;
// ====DECL======
Card::Card()
{
abilities = 0;
flavorText = 0;
keywords = 0;
artifact = 0;
classType = new char[strlen("Card") + 1];
classType = "Card";
}Card::~Card (){
delete name;
delete abilities;
delete flavorText;
artifact = NULL;
}
// ------------
Card::Card(const Card & to_copy)
{
name = new char[strlen(to_copy.name) +1]; // creating dynamic array
strcpy(to_copy.name, name);
type = to_copy.type;
color = to_copy.color;
manaCost = to_copy.manaCost;
abilities = new char[strlen(to_copy.abilities) +1];
strcpy(abilities, to_copy.abilities);
flavorText = new char[strlen(to_copy.flavorText) +1];
strcpy(flavorText, to_copy.flavorText);
keywords = new char[strlen(to_copy.keywords) +1];
strcpy(keywords, to_copy.keywords);
inPlay = to_copy.inPlay;
tapped = to_copy.tapped;
enchanted = to_copy.enchanted;
cursed = to_copy.cursed;
if (to_copy.type != ARTIFACT)
artifact = to_copy.artifact;
}
// ====DECL=====
int Card::equipArtifact(Artifact* to_equip){
artifact = to_equip;
}
Artifact * Card::unequipArtifact(Card * unequip_from){
Artifact * to_remove = artifact;
artifact = NULL;
return to_remove;
// put card in hand or in graveyard
}
int Card::enchant( Card * to_enchant){
to_enchant->enchanted = true;
cout << "enchanted" << endl;
}
int Card::disenchant( Card * to_disenchant){
to_disenchant->enchanted = false;
cout << "Enchantment Removed" << endl;
}
// ========DECL=====
Spell::Spell()
{
currPower = basePower;
currToughness = baseToughness;
classType = new char[strlen("Spell") + 1];
classType = "Spell";
}
Spell::~Spell(){}
// ---------------
Spell::Spell(const Spell & to_copy){
currPower = to_copy.currPower;
basePower = to_copy.basePower;
currToughness = to_copy.currToughness;
baseToughness = to_copy.baseToughness;
}
// =========
int Spell::attack( Spell *& blocker ){
blocker->currToughness -= currPower;
currToughness -= blocker->currToughness;
}
//==========
int Spell::counter (Spell *& to_counter){
cout << to_counter->name << " was countered by " << name << endl;
}
// ============
int Spell::heal (Spell *& to_heal, int amountOfHealth){
to_heal->currToughness += amountOfHealth;
}
// -------
Creature::Creature(){
summoningSick = true;
}
// =====DECL======
Land::Land(){
color = NON;
classType = new char[strlen("Land") + 1];
classType = "Land";
}
// ------
int Land::generateMana(int mana){
// ... //
}
card.h
#ifndef CARD_H
#define CARD_H
#include <cctype>
#include <iostream>
#include "conception.h"
class Artifact;
class Spell;class Card : public Conception
{
public:
Card();
Card(const Card &);
~Card();
protected:
char* name;
enum CardType { INSTANT, CREATURE, LAND, ENCHANTMENT, ARTIFACT, PLANESWALKER};
enum CardColor { WHITE, BLUE, BLACK, RED, GREEN, NON };
CardType type;
CardColor color;
int manaCost;
char* abilities;
char* flavorText;
char* keywords;
bool inPlay;
bool tapped;
bool cursed;
bool enchanted;
Artifact* artifact;
virtual int enchant( Card * );
virtual int disenchant (Card * );
virtual int equipArtifact( Artifact* );
virtual Artifact* unequipArtifact(Card * );
};
// ------------
class Spell: public Card
{
public:
Spell();
~Spell();
Spell(const Spell &);
protected:
virtual int heal( Spell *&, int );
virtual int attack( Spell *& );
virtual int counter( Spell*& );
int currToughness;
int baseToughness;
int currPower;
int basePower;
};
class Land: public Card
{
public:
Land();
~Land();
protected:
virtual int generateMana(int);
};
class Forest: public Land
{
public:
Forest();
~Forest();
protected:
int generateMana();
};
class Creature: public Spell
{
public:
Creature();
~Creature();
protected:
bool summoningSick;
};
class Sorcery: public Spell
{
public:
Sorcery();
~Sorcery();
protected:
};
#endif
conception.h — это «супер класс», из которого все происходит
class Conception{
public:
Conception();
~Conception();
protected:
char* classType;
};
conception.cpp
Conception::Conception{
Conception(){
classType = new char[11];
char = "Conception";
}
game.cpp — это неполный класс на данный код
#include <iostream>
#include <cctype>
#include "game.h"#include "player.h"
Battlefield::Battlefield(){
card = 0;
}
Battlefield::~Battlefield(){
delete card;
}
Battlefield::Battlefield(const Battlefield & to_copy){
}
// ===========
/*
class Game(){
public:
Game();
~Game();
protected:
Player** player; // for multiple players
Battlefield* root; // for battlefield
getPlayerMove(); // ask player what to do
addToBattlefield();
removeFromBattlefield();
sendAttack();
}
*/
#endif
game.h
#ifndef GAME_H
#define GAME_H
#include "list.h"
class CardList();
class Battlefield : CardList{
public:
Battlefield();
~Battlefield();
protected:
Card* card; // make an array
};
class Game : Conception{
public:
Game();
~Game();
protected:
Player** player; // for multiple players
Battlefield* root; // for battlefield
getPlayerMove(); // ask player what to do
addToBattlefield();
removeFromBattlefield();
sendAttack();
Battlefield* field;
};
list.cpp
#include <iostream>
#include <cctype>
#include "list.h"
// ==========
LinkedList::LinkedList(){
root = new Node;
classType = new char[strlen("LinkedList") + 1];
classType = "LinkedList";
};
LinkedList::~LinkedList(){
delete root;
}
LinkedList::LinkedList(const LinkedList & obj)
{
// code to copy
}
// ---------
// =========
int LinkedList::delete_all(Node* root){
if (root = 0)
return 0;
delete_all(root->next);
root = 0;
}
int LinkedList::add( Conception*& is){
if (root == 0){
root = new Node;
root->next = 0;
}
else
{
Node * curr = root;
root = new Node;
root->next=curr;
root->it = is;
}
}
int LinkedList::remove(Node * root, Node * prev, Conception* is){
if (root = 0)
return -1;
if (root->it == is){
root->next = root->next;
return 0;
}
remove(root->next, root, is);
return 0;
}
Conception* LinkedList::find(Node*& root, const Conception* is, Conception* holder = NULL)
{
if (root==0)
return NULL;
if (root->it == is){
return root-> it;
}
holder = find(root->next, is);
return holder;
}Node* LinkedList::goForward(Node * root){
if (root==0)
return root;
if (root->next == 0)
return root;
else
return root->next;
}
// ============
Node* LinkedList::goBackward(Node * root){
root = root->prev;
}
list.h
#ifndef LIST_H
#define LIST_H
#include <iostream>
#include "conception.h"
class Node : public Conception {
public:
Node() : next(0), prev(0), it(0)
{ it = 0;
classType = new char[strlen("Node") + 1];
classType = "Node";
};
~Node(){
delete it;
delete next;
delete prev;
}
Node* next;
Node* prev;
Conception* it; // generic object
};
// ----------------------
class LinkedList : public Conception {
public:
LinkedList();
~LinkedList();
LinkedList(const LinkedList&);
friend bool operator== (Conception& thing_1, Conception& thing_2 );
protected:
virtual int delete_all(Node*);
virtual int add( Conception*& ); //
virtual Conception* find(Node *&, const Conception*, Conception* ); //
virtual int remove( Node *, Node *, Conception* ); // removes question with keyword int display_all(node*& );
virtual Node* goForward(Node *);
virtual Node* goBackward(Node *);
Node* root;
// write copy constrcutor
};
// =============
class CircularLinkedList : public LinkedList {
public:
// CircularLinkedList();
// ~CircularLinkedList();
// CircularLinkedList(const CircularLinkedList &);
};
class DoubleLinkedList : public LinkedList {
public:
// DoubleLinkedList();
// ~DoubleLinkedList();
// DoubleLinkedList(const DoubleLinkedList &);
protected:
};
// END OF LIST Hierarchy#endif
player.cpp
#include <iostream>
#include "player.h"#include "list.h"using namespace std;Library::Library(){
root = 0;
}
Library::~Library(){
delete card;
}
// ====DECL=========
Player::~Player(){
delete fname;
delete lname;
delete deck;
}
Wizard::~Wizard(){
delete mana;
delete rootL;
delete rootH;
}// =====Player======
void Player::changeName(const char[] first, const char[] last){
char* backup1 = new char[strlen(fname) + 1];
strcpy(backup1, fname);
char* backup2 = new char[strlen(lname) + 1];
strcpy(backup1, lname);
if (first != NULL){
fname = new char[strlen(first) +1];
strcpy(fname, first);
}
if (last != NULL){
lname = new char[strlen(last) +1];
strcpy(lname, last);
}
return 0;
}
// ==========
void Player::seeStats(Stats*& to_put){
to_put->wins = stats->wins;
to_put->losses = stats->losses;
to_put->winRatio = stats->winRatio;
}
// ----------
void Player::displayDeck(const LinkedList* deck){
}
// ================
void CardList::findCard(Node* root, int id, NodeCard*& is){
if (root == NULL)
return;
if (root->it.id == id){
copyCard(root->it, is);
return;
}
else
findCard(root->next, id, is);
}
// --------
void CardList::deleteAll(Node* root){
if (root == NULL)
return;
deleteAll(root->next);
root->next = NULL;
}
// ---------
void CardList::removeCard(Node* root, int id){
if (root == NULL)
return;
if (root->id = id){
root->prev->next = root->next; // the prev link of root, looks back to next of prev node, and sets to where root next is pointing
}
return;
}
// ---------
void CardList::addCard(Card* to_add){
if (!root){
root = new Node;
root->next = NULL;
root->prev = NULL;
root->it = &to_add;
return;
}
else
{
Node* original = root;
root = new Node;
root->next = original;
root->prev = NULL;
original->prev = root;
}
}
// -----------
void CardList::displayAll(Node*& root){
if (root == NULL)
return;
cout << "Card Name: " << root->it.cardName;
cout << " || Type: " << root->it.type << endl;
cout << " --------------- " << endl;
if (root->classType == "Spell"){
cout << "Base Power: " << root->it.basePower;
cout << " || Current Power: " << root->it.currPower << endl;
cout << "Base Toughness: " << root->it.baseToughness;
cout << " || Current Toughness: " << root->it.currToughness << endl;
}
cout << "Card Type: " << root->it.currPower;
cout << " || Card Color: " << root->it.color << endl;
cout << "Mana Cost" << root->it.manaCost << endl;
cout << "Keywords: " << root->it.keywords << endl;
cout << "Flavor Text: " << root->it.flavorText << endl;
cout << " ----- Class Type: " << root->it.classType << " || ID: " << root->it.id << " ----- " << endl;
cout << " ******************************************" << endl;
cout << endl;
// -------
void CardList::copyCard(const Card& to_get, Card& put_to){
put_to.type = to_get.type;
put_to.color = to_get.color;
put_to.manaCost = to_get.manaCost;
put_to.inPlay = to_get.inPlay;
put_to.tapped = to_get.tapped;
put_to.class = to_get.class;
put_to.id = to_get.id;
put_to.enchanted = to_get.enchanted;
put_to.artifact = to_get.artifact;
put_to.class = to_get.class;
put.to.abilities = new char[strlen(to_get.abilities) +1];
strcpy(put_to.abilities, to_get.abilities);
put.to.keywords = new char[strlen(to_get.keywords) +1];
strcpy(put_to.keywords, to_get.keywords);
put.to.flavorText = new char[strlen(to_get.flavorText) +1];
strcpy(put_to.flavorText, to_get.flavorText);
if (to_get.class = "Spell"){
put_to.baseToughness = to_get.baseToughness;
put_to.basePower = to_get.basePower;
put_to.currToughness = to_get.currToughness;
put_to.currPower = to_get.currPower;
}
}
// ----------
player.h
#ifndef player.h
#define player.h
#include "list.h"
// ============
class CardList() : public LinkedList(){
public:
CardList();
~CardList();
protected:
virtual void findCard(Card&);
virtual void addCard(Card* );
virtual void removeCard(Node* root, int id);
virtual void deleteAll();
virtual void displayAll();
virtual void copyCard(const Conception*, Node*&);
Node* root;
}
// ---------
class Library() : public CardList(){
public:
Library();
~Library();
protected:
Card* card;
int numCards;
findCard(Card&); // get Card and fill empty template
}
// -----------
class Deck() : public CardList(){
public:
Deck();
~Deck();
protected:
enum deckColor { WHITE, BLUE, BLACK, RED, GREEN, MIXED };
char* deckName;}
// ===============
class Mana(int amount) : public Conception {
public:
Mana() : displayTotal(0), classType(0)
{ displayTotal = 0;
classType = new char[strlen("Mana") + 1];
classType = "Mana";
};
protected:
int accrued;
void add();
void remove();
int displayTotal();
}
inline Mana::add(){ accrued += 1; }
inline Mana::remove(){ accrued -= 1; }
inline Mana::displayTotal(){ return accrued; }
// ================
class Stats() : public Conception {
public:
friend class Player;
friend class Game;
Stats() : wins(0), losses(0), winRatio(0) {
wins = 0; losses = 0;
if ( (wins + losses != 0)
winRatio = wins / (wins + losses);
else
winRatio = 0;
classType = new char[strlen("Stats") + 1];
classType = "Stats";
}
protected:
int wins;
int losses;
float winRatio;
void int getStats(Stats*& );
}
// ==================
class Player() : public Conception{
public:
Player() : wins(0), losses(0), winRatio(0) {
fname = NULL;
lname = NULL;
stats = NULL;
CardList = NULL;
classType = new char[strlen("Player") + 1];
classType = "Player";
};
~Player();
Player(const Player & obj);
protected:
// member variables
char* fname;
char* lname;
Stats stats; // holds previous game statistics
CardList* deck[]; // hold multiple decks that player might use - put ll in this
private:
// member functions
void changeName(const char[], const char[]);
void shuffleDeck(int);
void seeStats(Stats*& );
void displayDeck(int);
chooseDeck();
}
// --------------------
class Wizard(Card) : public Player(){
public:
Wizard() : { mana = NULL; rootL = NULL; rootH = NULL};
~Wizard();
protected:
playCard(const Card &);
removeCard(Card &);
attackWithCard(Card &);
enchantWithCard(Card &);
disenchantWithCard(Card &);
healWithCard(Card &);
equipWithCard(Card &);
Mana* mana[];
Library* rootL; // Library
Library* rootH; // Hand
}
#endif
По крайней мере, одна из ваших проблем заключается в том, что в «player.h» у вас есть
#ifndef player.h
#define player.h
«player.h» не является допустимым символом препроцессора. Ты имел ввиду
#ifndef player_h
#define player_h
?
Во-вторых, conception.cpp ничего не включает.
В-третьих, определения вашего класса в значительной степени недействительны.
class Foo()
не является законным и не является
class Foo() : public class Bar()
Какое отношение «()» имеет к имени класса? Вы думаете о конструкторе?
Тогда есть это
char = "Conception";
Вы не можете присвоить значение типу.
—— Обратная связь, чтобы помочь вам очистить код ——
. Выбрать стиль
Или — если вы работаете с чужим кодом, возьмите его.
Но придерживайтесь этого.
Огромный процент дефектов программного обеспечения, прошедших первоначальную разработку, существует потому, что их было трудно обнаружить — пропущены точки с запятой, пропущены сложные выражения и т. Д. C.f. «CARD_H» против «player.h».
. Несоответствие является причиной большинства ошибок
classType = new char[11];
char = "Conception";
Вы, наверное, имеете в виду
classType = new char[11];
classType = "Conception";
но это утечка памяти и ошибка, ожидающая своего появления. В Card :: вы делаете это более правильно
name = new char[strlen(to_copy.name) +1]; // creating dynamic array
strcpy(to_copy.name, name);
Версия, которую вы используете в другом месте
classType = new ...
classType = "String";
выделяет некоторую память, сохраняет адрес в classType. Затем он ищет переменную скомпилированного массива char * «String \ 0» и вместо этого сохраняет свой адрес в classType.
Когда класс исчезнет, он попытается удалить статическую строку и произойдет сбой.
Если это учебное упражнение, и вы пытаетесь научиться управлению памятью, этот общий подход может быть достаточно справедливым. Но размещение владения указателями в ваших классах, как это — верный путь к утечкам памяти и неопределенным ошибкам в поведении.
Лучше всего инкапсулировать указатели в класс в стиле RAII (класс, который владеет указателем и выполняет удаление, когда он выходит из области видимости). Взгляните на «std :: unique_ptr», «std :: shared_ptr» и «std :: weak_ptr». Для ваших целей «std :: string» может помочь вам уменьшить количество дефектов, устраняя большую часть управленческих накладных расходов.
. Старайтесь не смешивать списки инициализаторов со списками назначений.
Как правило, лучше использовать один или другой. Вы, вероятно, можете избежать использования списков инициализаторов, когда все ваши участники могут быть инициализированы таким образом, но если они не могут, может быть лучше использовать назначение.
Foo() : m_a(), m_b(), m_c() { m_b = 1; m_c = 2; } // is m_a not having a value a bug or intentional?
. Различают переменные-члены от обычных переменных.
Вы столкнетесь с ошибками, когда значения исчезают из-за затенения: Теневые переменные
#include <iostream>
int i = 0;
int main() {
int i = 1;
for (int i = 0; i < 10; ++i) {
int i = 2 * i;
std::cout << i << std::endl;
}
return 0;
}
когда вы не различаете переменные-члены (многие люди используют префикс «m_», другие используют суффикс «_»), это случается с вами часто.
. Не назначайте числовые значения указателям.
name = 0;
в то время как это компилируется, вы настраиваете себя на менее очевидные случаи, которые кажутся числами и плохими вещами.
abilities = 0;
Нет, я супермен, у меня ВСЕ способности.
abilities = 42;
Еще два правильных способа сделать это
name = NULL; // Traditional C++
или же
name = nullptr; // C++11
Вы сделали это в некоторых местах, опять же последовательность не подводит вас.
. (незначительный, но он укусит вас в задницу через несколько недель) «это» обычно используется для ссылки на «итератор», вы можете использовать «данные» или «значение» или «элемент».
. не делайте членов классов / объектов публичными.
Ваш класс «Node» выглядит невероятно глючным (деструктор удаляет как prev, так и next ???), и вы не можете судить по классу, как устанавливается указатель «it», предположительно, потому что это происходит в другом месте. Где еще вы вмешиваетесь в указатели «it», prev и next? Инкапсуляция.
. ‘const’ может быть твоим другом (будучи болью в твоей заднице)
if (to_get.class = «Spell») {
Это назначит «Spell» для to_get.class, что приведет к утечке памяти и другим проблемам, а затем завершится успешно — «Spell» вычислит фиксированный адрес const char *, который не равен нулю, что, следовательно, является истиной.
(Он также не компилируется, потому что «class» — это ключевое слово, а фактическая переменная — «className»).
Вы можете предотвратить это, защищая своих реальных участников и выставляя их только через тщательно выбранных участников.
const char* Class() const { return m_className; }
Позвольте мне сломать это:
const char* :- you cannot modify the contents,
Class() :- instead of to_get.class you'll use to_get.Class()
const :- this function does not have side-effects on the object
Последняя часть означает, что она может быть использована для объекта const.
class Beer {
bool m_isFull;
public:
Beer() : m_isFull(true) {}
// non-const function, has side-effects (changes isFull);
void drink() { m_isFull = false; }
// const function, returns a copy of "m_isFull". you can
// change the value that's returned, but it doesn't affect us.
void isFull() const { return m_isFull; }
// example of a non-const accessor, if you REALLY want
// the caller to be able to modify m_isFull for some reason.
const bool& getIsFull() { return m_isFull; }
};
. И наконец: научиться изолировать концепции и алгоритмы.
Много ошибок / ошибок / ошибок в коде, кажется, потому что вы не на 100% с некоторыми нюансами или даже деталями. Это не лишено смысла, но вам нужно найти способ опробовать маленькие кусочки языка.
Потратьте немного времени, чтобы научиться развертывать микропрограммы на чем-то вроде ideone.com. Если вы используете Linux, создайте себе каталог «srctest» с «test.cpp» и «test.h» и Makefile
Makefile
all: srctest
srctest: srctest.cpp srctestextern.cpp srctest.h
g++ -o srctest -Wall -ggdb srctest.cpp srctestextern.cpp
srctest.cpp
#include "srctest.h"#include <iostream>
// add your other includes here and just leave them.
int main() {return 0;
}
srctest.h
#ifndef SRCTEST_SRCTEST_H
#define SRCTEST_SRCTEST_H
// anything I want to test in a .h file here
#endif
srctestextern.cpp
#include "srctest.h"
// Anything you want to test having in a separate source file goes here.
Если вы используете visual studio, настройте себе нечто подобное.
Идея состоит в том, чтобы где-то, где вы могли бы пойти и вставить несколько строк кода, и вам было бы удобно переходить к тому, что вы пытаетесь отладчиком.
Способность быстро локализовать проблемы — это ключевая часть успеха программиста, а не работающего обезьяны кода.
Других решений пока нет …