How to do seperate declarartion and definition of member variables, static member variables and static functions.

Hi ppl :),

How can we declare and define static class data members separately in .h and respective .cpp file.

Here is the .h file : animal_factory.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#ifndef ANIMAL_FACTORY_H_
#define ANIMAL_FACTORY_H_

#include "animal.h"
#include "cat.h"
#include "dog.h"
#include <map>
#include <cstring>

class AnimalFactory
{
    private:
        typedef std::map<std::string, CreateAnimalFn> FactoryMap;
        extern FactoryMap factoryMap;     //declaraton, how to define in .cxx
        extern static AnimalFactory *animalFactory;  //declaration, how to define in cxx

    public:
        static AnimalFactory* getAnimalFactory();  //how to define in cxx
        void Register(const std::string &, CreateAnimalFn);
        Animal* createAnimal(const std::string &, unsigned int);
};

#endif 
in animal_factory.cxx
1
2
3
4
5
6
7
#include "animal_factory.h"

AnimalFactory::FactoryMap  factoryMap /* initialise if required */ ;

AnimalFactory* AnimalFactory::animalFactory = nullptr ; // TO Do: initialise with a non-null pointer

AnimalFactory* AnimalFactory::getAnimalFactory() { return animalFactory ; }
Thanks alot @JLBorges for this clarification :)
@OP,

@JLBorges answered your question. However, you might want to consider the header files you included in your animal_factory.h. I don't see any mention of cats or dogs in your header, so there is no reason to include cat.h or dog.h. Additionally, since you only reference an Animal*, you can simply forward declare Animal rather than include the header file.

1
2
3
4
5
6
7
...
class Animal;

...

    Animal* createAnimal(const std::string &, unsigned int);
...


These may seem like minor things, but as your programs get more involved, unnecessary headers can lead to unexpected dependencies which can cause rebuilds to take longer than expected. In worst cases, you can develop circular dependencies which can cause builds to fail. It's always best to limit the number of header files included in a header file.

Also, you include <cstring> which is (essentially) the C string.h file, but you are using C++'s std::string class. You should include <string> instead.

@doug4,
Thanks alot for taking out time for this insightful addition.

I'd be glad if you could let me know if we could do the intended thing without including these headers.

The intent of the program is to create a singleton factory (AnimalFactory) that returns an animal object pointer based on the string passed to createAnimal(....).

Is there a we do not need to include animal.h, cat.h, dog.h in the animal_factory.h file. I included them because Register function maps the values of string (animal family (cat or dog)) to the create function defined in that class.

Here is the code for reference, in case you would like to have a look.



animal.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#ifndef _ANIMAL_INSTANCE
#define _ANIMAL_INSTANCE

class Animal
{
    public:
        unsigned int nLegs;
        
        Animal(unsigned int p_nLegs);
        unsigned int getLegs();
        virtual void speak() = 0;
};

typedef Animal* (*CreateAnimalFn)(unsigned int);

#endif 


animal.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
#ifndef ANIMAL_CPP_
#define ANIMAL_CPP_

#include "animal.h"

Animal::Animal(unsigned int p_nLegs) : nLegs(p_nLegs) {}

unsigned int Animal::getLegs()
{
    return nLegs;
}

#endif 


cat.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#ifndef CAT_H_
#define CAT_H_
#include "animal.h"

class Cat : public Animal
{
    public:
        Cat(unsigned int p_nLegs);
        virtual void speak();

        static Animal* create(unsigned int);
};

#endif 


cat.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include "cat.h"
#include <iostream>

Cat::Cat(unsigned int p_nLegs) : Animal(p_nLegs) {}

void Cat::speak()
{
    std::cout << "\n I am a cat with legs = " << nLegs;
    return;
}

Animal* Cat::create(unsigned int p_nLegs)
{
    return new Cat(p_nLegs);
}



dog.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#ifndef DOG_H_
#define DOG_H_

#include "animal.h"

class Dog : public Animal
{
    public:
        Dog(unsigned int p_nLegs);
        virtual void speak();

        static Animal* create(unsigned int);
};

#endif 



dog.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include "dog.h"
#include <iostream>

Dog::Dog(unsigned int p_nLegs) : Animal(p_nLegs) {}

void Dog::speak()
{
    std::cout << "\n Dog Dog " << nLegs;
    return;
}

Animal* Dog::create(unsigned int p_nLegs)
{
    return new Dog(p_nLegs);
}




abimal_factory.h
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
#ifndef ANIMAL_FACTORY_H_
#define ANIMAL_FACTORY_H_

#include "animal.h"
#include "cat.h"
#include "dog.h"
#include <map>
#include <cstring>

class AnimalFactory
{
    private:
        AnimalFactory();
        AnimalFactory(const AnimalFactory &);
        AnimalFactory & operator=(const AnimalFactory &);
        
        typedef std::map<std::string, CreateAnimalFn> FactoryMap;
        FactoryMap factoryMap;
        static AnimalFactory *animalFactory;

    public:
        static AnimalFactory* getAnimalFactory();
        void Register(const std::string &, CreateAnimalFn);
        Animal* createAnimal(const std::string &, unsigned int);
};

#endif 



animal_factory.cpp
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
#include "animal_factory.h"

AnimalFactory* AnimalFactory::animalFactory = nullptr;

AnimalFactory::AnimalFactory() 
{
    Register("cat", &Cat::create);
    Register("dog", &Dog::create);
}

AnimalFactory::AnimalFactory(const AnimalFactory &) {}

AnimalFactory & AnimalFactory::operator=(const AnimalFactory &) { return *this;}

AnimalFactory* AnimalFactory::getAnimalFactory()
{
    if(animalFactory == nullptr)
        return new AnimalFactory();
    return animalFactory;
}

void AnimalFactory::Register(const std::string &s, CreateAnimalFn fPtr)
{
    factoryMap[s] = fPtr;
}

Animal* AnimalFactory::createAnimal(const std::string &s, unsigned int p_nLegs)
{
    auto it = factoryMap.find(s);

    if(it != factoryMap.end())
        return it->second(p_nLegs);

    return nullptr;
}



Thanks :)
Is there a we do not need to include animal.h, cat.h, dog.h in the animal_factory.h file. I included them because Register function maps the values of string (animal family (cat or dog)) to the create function defined in that class.


Yes. But you don't use them in the header file. You use them in the source file. Include them there.

So, in animal_factory.h, you can remove lines 5 & 6. In animal_factory.cpp you need to include them. Earlier I didn't notice the reference to CreateAnimalFn in animal.h, so you do need to include animal.h in animal_factory.h for that definition.
Last edited on
Topic archived. No new replies allowed.