I keep getting loads of linker errors that probably have something to do with virtual-functions/definitions and/or static class members...
I've seen several relevant posts but none of the solutions suggested work,
can you see wht the problem is here?

My projects consists of 3 files:

BALLS.H

#include <iostream>

using namespace std;

class Ball{                     //Abstract Class!!
 protected:                     //no Balls will be constructed
    int durability;
    bool hidden;
 public:
    Ball(int dur=0) :durability(dur), hidden(false){}
    virtual void hit(){}
    virtual void rest()=0;
    virtual int get_state() {}
};


class Basket : public Ball {
    public:
        Basket(int L1) :Ball(L1)
        {   cout<<"New basketball!"<<endl;
            count++;
        }
        void rest(){}
        int get_state();
        void hit();

        static int count;
};


class Tennis : public Ball {
    public:
        Tennis(int L2) :Ball(L2)
        {   cout<<"New tennis ball!"<<endl;
            count++;
        }
        void rest(){ Ball::durability=Ball::durability+3; }
        int get_state();
        void hit();

        static int count;
};


class Ping_pong : public Ball {
 private:
        bool broken;
 public:
        Ping_pong(int L3) :Ball(L3), broken(false)
        {   cout<<"New ping-pong ball!"<<endl;
            count++;
        }
        void rest(){ Ball::durability++; }
        int get_state();
        void hit();

        static int count;
};

BALLS.CPP

#include <iostream>
#include <cstdlib>
#include "Balls.h"

using namespace std;


void Basket::hit(){
    int to_hell;
    if(!hidden){
        if(durability){
            if(!(to_hell=rand()%2)){
                cout<<"Tsaf!"<<endl;
                durability--;
            }
            else{
                cout<<"Oh, what a hit! The ball is gone!"<<endl;
                hidden=true;
            }
        }
        else
            cout<<"Plof!"<<endl;
    }
    else
        cout<<"You cannot hit a hidden ball!"<<endl;
}


void Tennis::hit(){
    int to_hell;
    if(!hidden){
        if(durability){
            if(!(to_hell=rand()%2)){
                cout<<"Tsaf!"<<endl;
                durability=durability-5;
                if(durability<0) durability=0;
            }
            else{
                cout<<"Oh, what a hit! The ball is gone!"<<endl;
                hidden=true;
            }
        }
        else
            cout<<"Plof!"<<endl;
    }
    else
        cout<<"You cannot hit a hidden ball!"<<endl;
}


void Ping_pong::hit(){
    int to_hell, sudn_brk;
    if(!broken){
        if(!hidden){
            if(durability){
                if(!(to_hell=rand()%2)){
                    cout<<"Tsaf!"<<endl;
                    if(!(sudn_brk=rand()%2)){
                        durability--;;
                        if(durability<0) durability=0;
                    }
                    else{
                        cout<<"Bam! Ball broken!"<<endl;
                        broken=true;
                    }
                }
                else{
                    cout<<"Oh, what a hit! The ball is gone!"<<endl;
                    hidden=true;
                }
            }
            else
                cout<<"Plof!"<<endl;
            }
        else
            cout<<"You cannot hit a hidden ball!"<<endl;
    }
    else
        cout<<"No point trying to hit a broken ball!"<<endl;
}



int Basket::get_state(){
    if(hidden){
        count--;
        return -1;
    }
    if(!durability) count--;
    return durability;
}

int Tennis::get_state(){
    if(hidden){
        count--;
        return -1;
    }
    if(!durability) count--;
    return durability;
}

int Ping_pong::get_state(){
    if(hidden){
        count--;
        return -1;
    }
    if(broken){
        count--;
        return -2;
    }
    if(!durability) count--;
    return durability;
}

and MAIN.CPP to test my model

#include <iostream>
#include <cstdlib>
#include <cctype>
#include <string>
#include "Balls.h"

using namespace std;


int main(int argc, char* argv[]){
    if(argc!=6){
        cout<<"Wrong number of arguments given"<<endl;
        return 0;
    }
    else{
        int L1,L2,L3,N,K;                                       //Managing command line arguments
        L1=atoi(argv[1]);
        L2=atoi(argv[2]);
        L3=atoi(argv[3]);
        N=atoi(argv[4]);
        K=atoi(argv[5]);
        if(!((0<L3)&&(L3<L2)&&(L2<L1))){                       //Cheching for durability requirements
            cout<<"Initial durabilities should be specifically sorted"
            <<"and positive (no worn-out balls from scratch)"<<endl;
            return 0;
        }

        srand(time(NULL));
        Basket::count=0;
        Tennis::count=0;
        Ping_pong::count=0;

        cout<<"So let's get "<<N<<" balls.."<<endl;             //Creating an array of NULL pointers
        Ball** Inventory= new Ball*[N];
        int i;
        for(i=0;i<N;i++){                                       //Dereferencing each pointer to
                                                                // newely created random-typed Balls
            int type=rand()%3+1;
            switch(type){
                case 1:
                    Inventory[i]=new Basket(L1);
                    break;
                case 2:
                    Inventory[i]=new Tennis(L2);
                    break;
                case 3:
                    Inventory[i]=new Ping_pong(L3);
                    break;
            }
        }

        int choice;
        int state;
        Ball *p;
        cout<<"Now let's hit some balls!"<<endl;
        for(i=0;i<K;i++){                                    //In each of the K rounds...
            choice=rand()%N+1;
            cout<<"Ball #"<<choice<<" chosen for the hit..."<<endl;
            p=Inventory[choice-1];
            p->hit();                                           //...select and hit a random ball...
            int j;
            for(j=0;j<N;j++){                                   //...and give the others a break
                p=Inventory[j];
                if(j!=choice-1) p->rest();
            }
            for(j=0;j<N;j++){                                   //Eventually, print-out each ball's condition
                p=Inventory[j];
                state=p->get_state();
                if(state==-1)      cout<<"Ball #"<<j+1<<" hidden!"<<endl;
                else if(state==-2) cout<<"Ball #"<<j+1<<" broken!"<<endl;
                else cout<<"Ball #"<<j+1<<" has "<<state<<" durability"<<endl;
            }
        }

        int b_count=Basket::count;                              //After the hit sessions, count the balls left for each type
        int t_count=Tennis::count;
        int p_count=Ping_pong::count;


        int max=b_count;                                        //...and find the fittest...
        string sport="Basket";
        if(t_count>max){
            max=t_count;
            sport="Tennis";
        }
        if(p_count>max){
            max=p_count;
            sport="Ping pong";
        }

        cout<<"Since we have the most balls left ("<<max        //...to choose our afternoon pastime!
            <<")... Let's play "<<sport<<'!'<<endl;

        return 1;
    }
}

and then

linux10:/home/users/sdi1200184/askhseis/ask3/ver3.0(static_counts)>
linux10:/home/users/sdi1200184/askhseis/ask3/ver3.0(static_counts)>g++ -o test m                                                       ain.cpp Balls.cpp
/tmp/ccFII2FB.o: In function `main':
main.cpp:(.text+0x112): undefined reference to `Basket::count'
main.cpp:(.text+0x11c): undefined reference to `Tennis::count'
main.cpp:(.text+0x126): undefined reference to `Ping_pong::count'
main.cpp:(.text+0x4e1): undefined reference to `Basket::count'
main.cpp:(.text+0x4ea): undefined reference to `Tennis::count'
main.cpp:(.text+0x4f3): undefined reference to `Ping_pong::count'
/tmp/ccFII2FB.o: In function `Basket::Basket(int)':
main.cpp:(.text._ZN6BasketC2Ei[_ZN6BasketC5Ei]+0x46): undefined reference to `Ba                                                       sket::count'
main.cpp:(.text._ZN6BasketC2Ei[_ZN6BasketC5Ei]+0x4e): undefined reference to `Ba                                                       sket::count'
/tmp/ccFII2FB.o: In function `Tennis::Tennis(int)':
main.cpp:(.text._ZN6TennisC2Ei[_ZN6TennisC5Ei]+0x46): undefined reference to `Te                                                       nnis::count'
main.cpp:(.text._ZN6TennisC2Ei[_ZN6TennisC5Ei]+0x4e): undefined reference to `Te                                                       nnis::count'
/tmp/ccFII2FB.o: In function `Ping_pong::Ping_pong(int)':
main.cpp:(.text._ZN9Ping_pongC2Ei[_ZN9Ping_pongC5Ei]+0x4d): undefined reference                                                        to `Ping_pong::count'
main.cpp:(.text._ZN9Ping_pongC2Ei[_ZN9Ping_pongC5Ei]+0x55): undefined reference                                                        to `Ping_pong::count'
/tmp/ccLOf5p1.o: In function `Basket::get_state()':
Balls.cpp:(.text+0x3b3): undefined reference to `Basket::count'
Balls.cpp:(.text+0x3bb): undefined reference to `Basket::count'
Balls.cpp:(.text+0x3d1): undefined reference to `Basket::count'
Balls.cpp:(.text+0x3d9): undefined reference to `Basket::count'
/tmp/ccLOf5p1.o: In function `Tennis::get_state()':
Balls.cpp:(.text+0x3f5): undefined reference to `Tennis::count'
Balls.cpp:(.text+0x3fd): undefined reference to `Tennis::count'
Balls.cpp:(.text+0x413): undefined reference to `Tennis::count'
Balls.cpp:(.text+0x41b): undefined reference to `Tennis::count'
/tmp/ccLOf5p1.o: In function `Ping_pong::get_state()':
Balls.cpp:(.text+0x437): undefined reference to `Ping_pong::count'
Balls.cpp:(.text+0x43f): undefined reference to `Ping_pong::count'
Balls.cpp:(.text+0x456): undefined reference to `Ping_pong::count'
Balls.cpp:(.text+0x45e): undefined reference to `Ping_pong::count'
Balls.cpp:(.text+0x474): undefined reference to `Ping_pong::count'
/tmp/ccLOf5p1.o:Balls.cpp:(.text+0x47c): more undefined references to `Ping_pong                                                       ::count' follow
collect2: ld returned 1 exit status
linux10:/home/users/sdi1200184/askhseis/ask3/ver3.0(static_counts)>

Recommended Answers

All 3 Replies

You have static data in some of the classes that also need to be declared globally in one of the *cpp files. Static class data is just like normal global data except they contain the class scope operator.

For example you might declare them in main.cpp like this example

#include <iostream>
#include <cstdlib>
#include <cctype>
#include <string>
#include "Balls.h"
using namespace std;

int Basket::count = 0; // <<<<<<<<<<<<<<<<<<<<<

int main(int argc, char* argv[]){
    if(argc!=6){

Thanks a lot it works now...

What i can't understand though is that since the "#include 'Balls'" commands the preprocessor(before calling the compiler or the linker!) to replace it with the .h file contents, the static field are therefore declared in the cpp file...

Why doing it again fixes the problem(and doesn't create others like shadowing declarations and sh..)??

Oh and sorry for the mistaken topic... It's a c++ issue not a c one!

Because c++ standards stay that's the way it has to be done. Just declaring an object static in the class declaration isn't enough -- the static objects also have to be declared just like ordinary global data; that's actually what they are.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.