tags:

views:

68

answers:

2

Most of the time, I "avoid" to have the following style in my single header file.

class a {
    void fun();
};

void a::fun() {
}

In order to avoid the following error. I try to separate class definition in cpp file and class declaration in h file. For example, the below is the wrong example :


main.cpp

#include "b.h"
#include "a.h"

int main()
{
    a aa;
    b bb;
}


a.h

#ifndef A_H
#define A_H

#include <iostream>

class a {
public:
    virtual int fun();
};


int a::fun()
{
    int t;
    std::cout << "a" << std::endl;
    return t;
}

#endif


b.h

#ifndef B_H
#define B_H

#include <iostream>
#include "a.h"

class b {
public:
    b();
};

#endif


b.cpp

#include "b.h"
#include "a.h"

b::b()
{
    a aa;
    aa.fun();
}

I will get the following error :

1>b.obj : error LNK2005: "public: virtual int __thiscall a::fun(void)" (?fun@a@@UAEHXZ) already defined in main.obj

However, when come to template, I will usually do it this way :

a.h

#ifndef A_H
#define A_H

#include <iostream>

template <typename T>
class a {
public:
    virtual T fun();
};


template<typename T> T a<T>::fun()
{
    T t;
    std::cout << "a" << std::endl;
    return t;
}

#endif

May I know it this a good practice?

Thanks.

Cheok

+2  A: 

You can eliminate the LNK2005 error by declaring the definition of a::fun() as inline. For example:

// a.h

// ...

inline int a::fun()
{
    int t;
    std::cout << "a" << std::endl;
    return t;
}

With templates, the problem doesn't occur because the compiler/linker take care of ensuring that there is only one definition of each template instantiation.

If, for some reason, you don't want the function to be inline, then you'll have to ensure that it only gets compiled once. For example, something like this:

// a.h

// ...

#ifdef DEFINE_CLASS_A_FUNCTIONS

int a::fun()
{
    int t;
    std::cout << "a" << std::endl;
    return t;
}

#endif

and then, somewhere, you'll need to do something like this (exactly once):

#define DEFINE_CLASS_A_FUNCTIONS
#include "a.h"
Kristopher Johnson
declaring a virtual function as inline doesn't seem to be correct.
Naveen
http://www.parashift.com/c%2B%2B-faq-lite/value-vs-ref-semantics.html#faq-31.6
aJ
@Naveen Why not? The compiler can and will inline the function if he can, otherwise he will ignore the inline. If it is declared as inline he will take care of the one definition rule.
TimW
I was a bit confused..More Effective C++ (Scott Mayers) Item 24 says, there may be a problem if ALL the virtual methods in a class are inline. In that case v-table for the class may be generated in all object files that include this class
Naveen
I do not plan to inline the function.
Yan Cheng CHEOK
+1  A: 

1>b.obj : error LNK2005: "public: virtual int __thiscall a::fun(void)" (?fun@a@@UAEHXZ) already defined in main.obj

You are getting this error because a::fun() is not inline

inline int a::fun()
{
    int t;
    std::cout << "a" << std::endl;
    return t;
}

Also, refer C++ FAQ : How can I avoid linker errors with my template functions?

aJ