从另一个 class 模块引用在 main 中创建的 class 实例
Referencing an instance of a class created in main from another class module
我正在研究一种需要两副牌的扑克游戏。出于统计原因,重要的是在洗牌两副牌时使用一个共同的随机数生成器。为了进行测试,我有一个小的 main,我在其中创建了一个随机数生成器实例和两个 deck 实例。我用语句“extern classRNG Random”引用 classDeck 中的实例“Random”。
一切编译正常,但我收到链接器错误“Deck.obj:错误 LNK2001:未解析的外部符号“class classRNG Random”(?Random@@3VclassRNG@@A)。”如果我在 classDeck 而不是在 main 中创建实例 Random,一切都会编译和链接 OK,但当然这会为每个 deck 创建一个单独的随机数生成器。
显然我忽略了一些东西。
要处理的代码很多,但我认为错误是由 Deck.cpp 中接近 Deck.cpp 末尾的函数“Shuffle”造成的。那就是我有语句“extern classRNG Random”。注释掉行“RawDeck[i].SortParam = Random.RNGGet()”消除了错误。
这是 RNG.h 的代码:
#ifndef RNG_H
#define RNG_H
class classRNG
{
private:
static unsigned long long Seed;
public:
classRNG(); // Default constructor;
classRNG(unsigned long long ullSeed); // Constructor with initial seed
unsigned long long RNGGet(); //Get a random number
};
#endif
RNG.cpp:
#include <iostream>
#include <vector>
#include <string>
#include <math.h>
#include <stdbool.h>
#include "RNG.h"
using namespace std;
const unsigned long long T1 = 60LL, T2 = 59LL;
classRNG::classRNG() // Default constructor
{
int i;
Seed = 3;
for (i=0; i<7*T1; i++) //Step thru some numbers to stabilize
{
RNGGet();
}
};
classRNG::classRNG(unsigned long long ullSeed) // Constructor with initial seed
{
const unsigned long long Mask1 = powl(2LL,T1);
const unsigned long long Mask = Mask1 - 2LL;
int i;
Seed = ullSeed % Mask;
for (i=0; i<7*T1; i++) //Step over trivial numbers
{
RNGGet();
}
};
// This method is used to obtain a random number. It returns an unsigned Long Long.
unsigned long long classRNG::RNGGet()
{
const long long Test1 = powl(2LL, T1-1LL);
const long long Test2 = powl(2LL, T2-1LL);
const unsigned long long Mask1 = powl(2LL,T1);
const unsigned long long Mask = Mask1 - 2LL;
const unsigned long long Taps = Test1 | Test2;
const unsigned long long Scram = 0x693474786E579bd % Mask;
unsigned long long Test;
Test = Seed & Taps;
Seed = (Seed << 1) & Mask;
if (Test == Test1 | Test == Test2){
Seed = Seed | 1LL;
}
return Seed * Scram;
};
unsigned long long classRNG::Seed = 3;
Deck.h:
#ifndef DECK_H
#define DECK_H
#include "struct_defs.h"
class classDeck
{
private:
static int NextCard; // Pointer to next card in the deck
static bool Ready; // Indicates that deck is not dirty
static structSortCard RawDeck[53]; // Stores the raw card value (1-52) with a sort parameter
bool SortDeck(int Plow, int Phi); // Used in Shuffle
void SwapCards(int P1, int P2); // Used in SortDeck
public:
classDeck(); //Constructor;
bool InitializeDeck();
bool Shuffle();
structCardDef GetCard();
bool DeckReady ();
};
#endif
Deck.cpp:
#include <iostream>
#include <vector>
#include <string>
#include <math.h>
#include <stdbool.h>
#include "RNG.h"
#include "struct_defs.h" // Data structures
#include "Deck.h"
using namespace std;
/*
This type manages the card deck. No data are directly exposed. It provides the following methods:
- InitializeDeck. Restores deck to unsorted state. (Probably never use this)
- Shuffle. Returns True when complete.
- GetCard. Returns the next card as Class classCardDef.
- DeckReady. Returns True if the deck is shuffled and not dirty.
*/
int classDeck::NextCard = 1;
bool classDeck::Ready = false;
structSortCard classDeck::RawDeck[] = {0};
classDeck::classDeck() //Constructor
{
InitializeDeck();
};
bool classDeck::SortDeck(int Plow, int Phi)
{
int Pivot, P1, P2, P3, i;
Ready = false;
// Check for trivial cases
if ((Phi - Plow) < 2) // Nothing to sort
{
return true;
}
if (((Phi - Plow) == 2) && RawDeck[Plow].SortParam > RawDeck[Phi].SortParam) // Only two - easy peasy
{
SwapCards(Phi, Plow);
return true;
}
// Set Pivot to last element
Pivot = Phi;
P3 = 0;
// Search for an element larger than the pivot, and set P1 to that
for (P1 = Plow; P1 < Pivot; P1++)
{
if(RawDeck[P1].SortParam > RawDeck[Pivot].SortParam) // Found a large number
{
// Search from P1+1 to Pivot-1 to find an element smaller than the pivot and set P2 to that
for (P2 = P1+1; P2 < Pivot; P2++)
{
if(RawDeck[P2].SortParam < RawDeck[Pivot].SortParam) // Found a small number
{
// Swap elements at P1 & P2
SwapCards(P1, P2);
P3 = P1; // Remember leftmost large card
break;
}
}
if (P2 >= Pivot) // Reached the pivot without finding another small card
{
break;
}
}
}
// Move Pivot to P3
if (P3 > 0) // There's at least one large card
{
SwapCards(P3, Pivot); // The Pivot is now at P3
}
// Split into two parts, and iterate any part with more than one element
Ready = SortDeck(Plow, P3 - 1) && SortDeck(P3 + 1, Phi);
return Ready;
};
void classDeck::SwapCards(int P1, int P2)
{
structSortCard Temp;
Temp.Value = RawDeck[P1].Value;
Temp.SortParam = RawDeck[P1].SortParam;
RawDeck[P1].Value = RawDeck[P2].Value;
RawDeck[P1].SortParam = RawDeck[P2].SortParam;
RawDeck[P2].Value = Temp.Value;
RawDeck[P2].SortParam = Temp.SortParam;
};
bool classDeck::InitializeDeck()
{
int i;
Ready = false;
for (i = 1; i <= 52; i++)
{
RawDeck[i].Value = i;
}
Ready = Shuffle();
return Ready;
};
bool classDeck::Shuffle()
{
int i;
extern classRNG Random;
Ready = false;
for (i = 1; i <= 52;i++)
{
RawDeck[i].SortParam = Random.RNGGet();
}
// Sort the deck
Ready = SortDeck(1, 52);
return Ready;
};
structCardDef classDeck::GetCard()
{
structCardDef NewCard;
int Card;
Ready = false;
Card = RawDeck[NextCard++].Value;
NewCard.Card = Card % 13 + 1;
NewCard.Suit = Card / 13 + 1;
return NewCard;
};
bool classDeck::DeckReady ()
{
return Ready;
};
最后,main.cpp
#include <iostream>
#include <vector>
#include <string>
#include <math.h>
#include <stdbool.h>
#include "RNG.h"
#include "struct_defs.h"
#include "Deck.h"
using namespace std;
int main()
{
unsigned long long X;
classRNG Random; // Create an instance of classRNG
X = Random.RNGGet();
// Create two decks
classDeck Deck[2];
结构“structSortCard”在“struct_defs.h”中定义为:
struct structSortCard
{
public:
int Value;
unsigned long long SortParam;
};
我试了很多东西都无济于事。
classRNG Random
是 main 的本地变量 - 它不是全局变量,因此在 classDeck::Shuffle
中的 extern
调用中不可见。使用 extern
来共享一个变量有点奇怪 - 为什么不让 Shuffle
接受一个 classRNG*
参数,这样你就可以将相同的 classRNG
传递给每个实例(或者你如果您愿意,可以在构造函数中传递它)。或者,您也可以使 RNG 成为 classDeck
的静态成员,这样套牌将负责构建一个在所有实例之间共享的 classRNG
。
这个声明
extern classRNG Random;
在全局命名空间中声明(但不定义)变量 Random
。
这个声明,同时在main
中定义了一个变量Random
int main()
{
unsigned long long X;
classRNG Random; // Create an instance of classRNG
//...
声明了一个在 main 的块范围之外不可见的局部变量。
因此在全局命名空间中声明的变量 Random
仍然未定义。
您可以将局部变量 Random
的声明(不带存储说明符 extern
)移动到函数 main 之前。在这种情况下,此声明将是全局命名空间中声明的变量 Random
的定义。
另一种方法是在 class classDeck
.
中创建 classRNG
类型的(静态)数据成员
我正在研究一种需要两副牌的扑克游戏。出于统计原因,重要的是在洗牌两副牌时使用一个共同的随机数生成器。为了进行测试,我有一个小的 main,我在其中创建了一个随机数生成器实例和两个 deck 实例。我用语句“extern classRNG Random”引用 classDeck 中的实例“Random”。
一切编译正常,但我收到链接器错误“Deck.obj:错误 LNK2001:未解析的外部符号“class classRNG Random”(?Random@@3VclassRNG@@A)。”如果我在 classDeck 而不是在 main 中创建实例 Random,一切都会编译和链接 OK,但当然这会为每个 deck 创建一个单独的随机数生成器。
显然我忽略了一些东西。
要处理的代码很多,但我认为错误是由 Deck.cpp 中接近 Deck.cpp 末尾的函数“Shuffle”造成的。那就是我有语句“extern classRNG Random”。注释掉行“RawDeck[i].SortParam = Random.RNGGet()”消除了错误。
这是 RNG.h 的代码:
#ifndef RNG_H
#define RNG_H
class classRNG
{
private:
static unsigned long long Seed;
public:
classRNG(); // Default constructor;
classRNG(unsigned long long ullSeed); // Constructor with initial seed
unsigned long long RNGGet(); //Get a random number
};
#endif
RNG.cpp:
#include <iostream>
#include <vector>
#include <string>
#include <math.h>
#include <stdbool.h>
#include "RNG.h"
using namespace std;
const unsigned long long T1 = 60LL, T2 = 59LL;
classRNG::classRNG() // Default constructor
{
int i;
Seed = 3;
for (i=0; i<7*T1; i++) //Step thru some numbers to stabilize
{
RNGGet();
}
};
classRNG::classRNG(unsigned long long ullSeed) // Constructor with initial seed
{
const unsigned long long Mask1 = powl(2LL,T1);
const unsigned long long Mask = Mask1 - 2LL;
int i;
Seed = ullSeed % Mask;
for (i=0; i<7*T1; i++) //Step over trivial numbers
{
RNGGet();
}
};
// This method is used to obtain a random number. It returns an unsigned Long Long.
unsigned long long classRNG::RNGGet()
{
const long long Test1 = powl(2LL, T1-1LL);
const long long Test2 = powl(2LL, T2-1LL);
const unsigned long long Mask1 = powl(2LL,T1);
const unsigned long long Mask = Mask1 - 2LL;
const unsigned long long Taps = Test1 | Test2;
const unsigned long long Scram = 0x693474786E579bd % Mask;
unsigned long long Test;
Test = Seed & Taps;
Seed = (Seed << 1) & Mask;
if (Test == Test1 | Test == Test2){
Seed = Seed | 1LL;
}
return Seed * Scram;
};
unsigned long long classRNG::Seed = 3;
Deck.h:
#ifndef DECK_H
#define DECK_H
#include "struct_defs.h"
class classDeck
{
private:
static int NextCard; // Pointer to next card in the deck
static bool Ready; // Indicates that deck is not dirty
static structSortCard RawDeck[53]; // Stores the raw card value (1-52) with a sort parameter
bool SortDeck(int Plow, int Phi); // Used in Shuffle
void SwapCards(int P1, int P2); // Used in SortDeck
public:
classDeck(); //Constructor;
bool InitializeDeck();
bool Shuffle();
structCardDef GetCard();
bool DeckReady ();
};
#endif
Deck.cpp:
#include <iostream>
#include <vector>
#include <string>
#include <math.h>
#include <stdbool.h>
#include "RNG.h"
#include "struct_defs.h" // Data structures
#include "Deck.h"
using namespace std;
/*
This type manages the card deck. No data are directly exposed. It provides the following methods:
- InitializeDeck. Restores deck to unsorted state. (Probably never use this)
- Shuffle. Returns True when complete.
- GetCard. Returns the next card as Class classCardDef.
- DeckReady. Returns True if the deck is shuffled and not dirty.
*/
int classDeck::NextCard = 1;
bool classDeck::Ready = false;
structSortCard classDeck::RawDeck[] = {0};
classDeck::classDeck() //Constructor
{
InitializeDeck();
};
bool classDeck::SortDeck(int Plow, int Phi)
{
int Pivot, P1, P2, P3, i;
Ready = false;
// Check for trivial cases
if ((Phi - Plow) < 2) // Nothing to sort
{
return true;
}
if (((Phi - Plow) == 2) && RawDeck[Plow].SortParam > RawDeck[Phi].SortParam) // Only two - easy peasy
{
SwapCards(Phi, Plow);
return true;
}
// Set Pivot to last element
Pivot = Phi;
P3 = 0;
// Search for an element larger than the pivot, and set P1 to that
for (P1 = Plow; P1 < Pivot; P1++)
{
if(RawDeck[P1].SortParam > RawDeck[Pivot].SortParam) // Found a large number
{
// Search from P1+1 to Pivot-1 to find an element smaller than the pivot and set P2 to that
for (P2 = P1+1; P2 < Pivot; P2++)
{
if(RawDeck[P2].SortParam < RawDeck[Pivot].SortParam) // Found a small number
{
// Swap elements at P1 & P2
SwapCards(P1, P2);
P3 = P1; // Remember leftmost large card
break;
}
}
if (P2 >= Pivot) // Reached the pivot without finding another small card
{
break;
}
}
}
// Move Pivot to P3
if (P3 > 0) // There's at least one large card
{
SwapCards(P3, Pivot); // The Pivot is now at P3
}
// Split into two parts, and iterate any part with more than one element
Ready = SortDeck(Plow, P3 - 1) && SortDeck(P3 + 1, Phi);
return Ready;
};
void classDeck::SwapCards(int P1, int P2)
{
structSortCard Temp;
Temp.Value = RawDeck[P1].Value;
Temp.SortParam = RawDeck[P1].SortParam;
RawDeck[P1].Value = RawDeck[P2].Value;
RawDeck[P1].SortParam = RawDeck[P2].SortParam;
RawDeck[P2].Value = Temp.Value;
RawDeck[P2].SortParam = Temp.SortParam;
};
bool classDeck::InitializeDeck()
{
int i;
Ready = false;
for (i = 1; i <= 52; i++)
{
RawDeck[i].Value = i;
}
Ready = Shuffle();
return Ready;
};
bool classDeck::Shuffle()
{
int i;
extern classRNG Random;
Ready = false;
for (i = 1; i <= 52;i++)
{
RawDeck[i].SortParam = Random.RNGGet();
}
// Sort the deck
Ready = SortDeck(1, 52);
return Ready;
};
structCardDef classDeck::GetCard()
{
structCardDef NewCard;
int Card;
Ready = false;
Card = RawDeck[NextCard++].Value;
NewCard.Card = Card % 13 + 1;
NewCard.Suit = Card / 13 + 1;
return NewCard;
};
bool classDeck::DeckReady ()
{
return Ready;
};
最后,main.cpp
#include <iostream>
#include <vector>
#include <string>
#include <math.h>
#include <stdbool.h>
#include "RNG.h"
#include "struct_defs.h"
#include "Deck.h"
using namespace std;
int main()
{
unsigned long long X;
classRNG Random; // Create an instance of classRNG
X = Random.RNGGet();
// Create two decks
classDeck Deck[2];
结构“structSortCard”在“struct_defs.h”中定义为:
struct structSortCard
{
public:
int Value;
unsigned long long SortParam;
};
我试了很多东西都无济于事。
classRNG Random
是 main 的本地变量 - 它不是全局变量,因此在 classDeck::Shuffle
中的 extern
调用中不可见。使用 extern
来共享一个变量有点奇怪 - 为什么不让 Shuffle
接受一个 classRNG*
参数,这样你就可以将相同的 classRNG
传递给每个实例(或者你如果您愿意,可以在构造函数中传递它)。或者,您也可以使 RNG 成为 classDeck
的静态成员,这样套牌将负责构建一个在所有实例之间共享的 classRNG
。
这个声明
extern classRNG Random;
在全局命名空间中声明(但不定义)变量 Random
。
这个声明,同时在main
中定义了一个变量Random
int main()
{
unsigned long long X;
classRNG Random; // Create an instance of classRNG
//...
声明了一个在 main 的块范围之外不可见的局部变量。
因此在全局命名空间中声明的变量 Random
仍然未定义。
您可以将局部变量 Random
的声明(不带存储说明符 extern
)移动到函数 main 之前。在这种情况下,此声明将是全局命名空间中声明的变量 Random
的定义。
另一种方法是在 class classDeck
.
classRNG
类型的(静态)数据成员