[Linker Error] undefined reference to -- answered

Hi folks!

I'm starting my assignment for c++ after working on java, and have a little problem that I can't seem to get rid of. When ever i try to compile my program, i get a ton of [Linker Error] undefined reference to *insert class::variable here* errors. Now I'm sure it's probably something that I've accidentally carried over from java, but even after a few hours on the net looking for answers, I can't seem to find one.

My code is as follows:

Main:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//a2mainApp.cpp

#include "validate.h"

int main( int argc, char *argv[] )
{
    const string COMMANDS[] = {"-i", "-o", "-p" };
    validate validation( COMMANDS[0], COMMANDS[1], COMMANDS[2] );

    if( !validation.isGoodCommandLine( argc, argv ) )
        exit(2); //bad commandLine

    const string inFileName = validation.getFileName( COMMANDS[0] );
    const string outFileName = validation.getFileName( COMMANDS[1] );
    const string opFileName = validation.getFileName( COMMANDS[2] );

}


validate.h"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//validate.h

#include <string>
using std::string;

class validate
{
    public:
        validate( string, string, string );
        bool isGoodCommandLine( int , char *[] );
        bool isGoodCommand( int count );
        bool isGoodSwitchCount();
        string getFileName( string );

    private:
        const static int COMMAND_COUNT = 3;
        const static int ARG_COUNT = 7;
        static string commands[ARG_COUNT];
        static string commandList[COMMAND_COUNT];
        static int switchCount[COMMAND_COUNT];
};


and finally, my implementation:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
//validation.cpp

#include "validate.h"

validate::validate( string firstCom, string secondCom, string thirdCom )
{
    for( int i = 0; i < validate::COMMAND_COUNT; ++i )
        validate::switchCount[i] = 0;

    validate::commandList[0] = firstCom;
    validate::commandList[1] = secondCom;
    validate::commandList[2] = thirdCom;
}

bool validate::isGoodCommandLine( int argCount, char *argValue[] )
{
    if( argCount != validate::ARG_COUNT )
        return false;

    for( int i = 0; i < validate::ARG_COUNT; ++i )
    {
        validate::commands[i].assign( argValue[i] );
        if( !isGoodCommand( i ) || !isGoodSwitchCount() )
            return false;
    }

    return true;
}

bool validate::isGoodCommand( int count )
{
    for( int i = 0; i < validate::COMMAND_COUNT; ++i )
    {
        if( validate::commands[count] == validate::commandList[i] ){
            ++validate::switchCount[i];
            return true;
        }
    }

    return false;
}

bool validate::isGoodSwitchCount()
{
    for( int i = 0; i < validate::COMMAND_COUNT; ++i )
    {
        if( validate::switchCount[i] > 1 )
            return false;
    }

    return true;
}

string validate::getFileName( string arg )
{
    bool found = false;
    int i;

    for( i = 1; i < validate::ARG_COUNT - 1 && found == false; i += 2 )
    {
        if( arg == validate::commands[i] )
            found = true;
    }

    if( found )
        return validate::commands[++i];
    else
        exit(1); //program fault
}



any help would be much appreciated.
Last edited on
I suspect it is because you have declared all your member variables as statics. The first two are OK as they are. You either need to take the static keyword out of the last three like this
1
2
3
4
5
6
    private:
        const static int COMMAND_COUNT = 3;
        const static int ARG_COUNT = 7;
        string commands[ARG_COUNT];
        string commandList[COMMAND_COUNT];
        int switchCount[COMMAND_COUNT];


or if they need to be static, put three lines at the top of validation.cpp like this
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//validation.cpp

#include "validate.h"

string validate::commands[ARG_COUNT];
string validate::commandList[COMMAND_COUNT];
int validate::switchCount[COMMAND_COUNT];

validate::validate( string firstCom, string secondCom, string thirdCom )
{
    for( int i = 0; i < validate::COMMAND_COUNT; ++i )
        validate::switchCount[i] = 0;

    validate::commandList[0] = firstCom;
    validate::commandList[1] = secondCom;
    validate::commandList[2] = thirdCom;
}


They don't appear to need to be static so I would recommend the first option. One problem that I have spotted are you for loops. By putting the double plus before the i you are incrementing i before each loop is executed so i will never be zero. Put the double plus after the i to increment after each loop is executed. For example, isGoodSwitchCount() needs to look like this
1
2
3
4
5
bool validate::isGoodSwitchCount()
{
    for( int i = 0; i < validate::COMMAND_COUNT; i++)
    {
     . . .


I have a couple of minor comments on your code. Although the line
 
using std::string;

in validation.h is perfectly valid, it is more usual to write
 
using namespace std;

unless you need to exclude the rest of the std namespace. Another point is that, again it is perfectly valid, but you do not need to put the validate:: prefix to reference symbols within the same class. The only reason for doing this would be if you have symbol name conflicts with another class you are using in which case the compiler will usually complain.

Nice clear coding style

Bertha

Thanks for the advice!

Turns out it was the static *smacks head into a wall* thanks!

To the best of my knowledge (aka, java), the incriment was done after all the code in the loop was finished, as such not altering the loop sequence, I may be wrong though, and its always better to be safe than sorry!

With the namespace std, my instructors have told us that somewhere in this program functions will be clashing. Besides that, as I'm just starting, I like to see where what I'm using is coming from. Though I use namespace for debugging purposes (to make sure i havent forgotten something).

Thanks for that! I'll make sure to check that out (as Im already getting sick of typing class names hehe).

Thanks, I tend to get lost in my own code if I dont keep it atleast semi-neat.

Kae
Last edited on
Topic archived. No new replies allowed.