Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
117 views
in Technique[技术] by (71.8m points)

c++ - Referencing an instance of a class created in main from another class module

I’m working on a variant of poker which requires two decks. For statistical reasons it’s important that when shuffling the two decks a common random number generator be used. For testing I have a small main where I create an instance of the random number generator and two instances of the deck. I reference to the instance “Random” in classDeck with the statement “extern classRNG Random.”

Everything compiles OK, but I get the linker error “Deck.obj : error LNK2001: unresolved external symbol "class classRNG Random" (?Random@@3VclassRNG@@A).” If I create the instance Random in classDeck instead of in main everything compiles and links OK, but of course that would create a separate random number generator for each deck.

There is clearly something I’m overlooking.

It's a lot of code to go through, but I think the error is being created by the function "Shuffle" in Deck.cpp, near the end of Deck.cpp. That's were I have the statement "extern classRNG Random." Commenting out the line "RawDeck[i].SortParam = Random.RNGGet()" eliminates the error.

Here’s the code for 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;
};

And finally, 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];

The structure "structSortCard" is defined in "struct_defs.h" as:

struct structSortCard
{
public:
    int Value;
    unsigned long long SortParam;
};

I've tried a lot of things to no avail.

question from:https://stackoverflow.com/questions/65892839/referencing-an-instance-of-a-class-created-in-main-from-another-class-module

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

classRNG Random is local to main - it's not a global variable so isn't visible in your extern call in classDeck::Shuffle. Using an extern to share a variable is a bit odd - why not either have Shuffle take a classRNG* parameter so you can pass the same classRNG to each instance (or you could pass it in the constructor if you prefer). Alternatively you could also make the RNG a static member of classDeck so the deck will be in charge of constructing exactly one classRNG that is shared amongst all instances.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...