Click here to Skip to main content
15,887,683 members
Please Sign up or sign in to vote.
1.00/5 (1 vote)
I have this odd issue, that I can make a declaration in a .h help file with Visual Studio 2013 for a c++ class; but if I try to define the class in the .h file, then I get an error:

I am accustomed to C where the .h file was simply appended to the top for the compiler and it did not make any difference whether the code was in the .h or the .cpp file as long as the order is correct. Why does it make a difference with Visual Studio 2013?

If I have this in the .h file, for example it compiles without an error:

CDCDirectControls.h file:
class CCDCDirectControls : private CView
{
	//Declaration portion
public:
	CCDCDirectControls(void);
	~CCDCDirectControls(void);
	//Definition portion of the class


};


CDCDirectControls.cpp file:
#include "stdafx.h"
#include "CDCDirectControls.h"

/*Default constructors and destructors*/
CCDCDirectControls::CCDCDirectControls(){ return; }  //Constructor does nothing for now - just methods are being accessed
CCDCDirectControls::~CCDCDirectControls(){ return; } //Destructor does nothing for now - just methods are being accessed


However, consider the below two blocks of C++; if I do this, I get a linker error:
C#
CDCDirectControls.obj : error LNK2005: "public: __thiscall CCDCDirectControls::CCDCDirectControls(void)" (??0CCDCDirectControls@@QAE@XZ) already defined in bmpLoadView.obj


CDCDirectControls.h file:
C++
class CCDCDirectControls : private CView
{
	//Declaration portion
public:
	CCDCDirectControls(void);
	~CCDCDirectControls(void);
	//Definition portion of the class


};


CDCDirectControls.cpp file:
C++
#include "stdafx.h"
#include "CDCDirectControls.h"

/*Default constructors and destructors*/
CCDCDirectControls::CCDCDirectControls(){ return; }  //Constructor does nothing for now - just methods are being accessed
CCDCDirectControls::~CCDCDirectControls(){ return; } //Destructor does nothing for now - just methods are being accessed


1) What is going on here? and 2) How is it possible to define the class members in the .h header file?

Update #1:

The following code compiles fine, with all the definition in the header file:

C++
#pragma once

class CDCDirectControls : private CView
{
	//Declaration portion
public:
	/*Default constructors and destructors*/
	CDCDirectControls::CDCDirectControls(){ return; };  //Constructor does nothing for now - just methods are being accessed
	CDCDirectControls::~CDCDirectControls(){ return; }; //Destructor does nothing for now - just methods are being accessed
	//CDCDirectControls(void);
	//~CDCDirectControls(void);
	//Definition portion of the class
	int testmethod1(void);


};

//Defintion portion

/*Default constructors and destructors*/
//CDCDirectControls::CDCDirectControls(){ return; };  //Constructor does nothing for now - just methods are being accessed
//CDCDirectControls::~CDCDirectControls(){ return; }; //Destructor does nothing for now - just methods are being accessed

inline int CDCDirectControls::testmethod1(void)
{
	return 5;
}

//test code taken from a C++ reference to see if a standard implementation works with VS 2013 C++:  http://www.icce.rug.nl/documents/cplusplus/cplusplus17.html

class Surround
{
	static int s_variable;
public:
	class FirstWithin
	{
		friend class Surround;
		friend class SecondWithin;
		static int s_varaible;
	public:
		int value();
	};
	int value();
private:
	class SecondWithin
	{
		friend class Surround;
		friend class FirstWithin;
		static int s_variable;
	public:
		int value();
	};

};

inline int Surround::value()
{
	return Surround::s_variable;
}


inline int Surround::FirstWithin::value()
{
	Surround::s_variable = SecondWithin::s_variable;
	return s_variable;
}

inline int Surround::SecondWithin::value()
{
	Surround::s_variable = FirstWithin::s_varaible;
	return s_variable;
}



It seems that there is something special about the constructor and perhaps also the destructor for the class with this compiler. The work-around is not to have a separate declaration from the definition. Preferable is a "do-nothing" definition in the c++ header file to start with; and if something is needed, that needs to be moved after to the .cpp file.

Updated:

What was driving this, is that sometimes it is necessary to reference to classes or methods declared later in the class; and if it is a method, than it can give an error if it is declared down the road. I duplicated the error with a constructor or not; I solved the inline problem by putting guards to the header.

I found that this code segment would compile:

C++
class CDCDirectControls : private CView
{
#ifndef CDCDirectControlsDefined
#define CDCDirectControlsDefined 1
	//Declaration portion
public:
	/*Default constructors and destructors*/

//	inline CDCDirectControls();  //Constructor does nothing for now
//	inline ~CDCDirectControls(); //Destructor does nothing for now
	//Definition portion of the class
	//int testmethod1(void);  //attempt forward declaration so that ::testmethod1 is exposed
	class b { public: b(){ CDCDirectControls c1; c1.CDCDirectControls::testmethod1(); } };
	//Defintion portion

//	inline CDCDirectControls::CDCDirectControls(){ return; }  //Constructor does nothing for now - just methods are being accessed
//	inline CDCDirectControls::~CDCDirectControls(){ return; } //Destructor does nothing for now - just methods are being accessed
	int testmethod1(void){ int x; x++; return x; };
	void CDCDirectControls::OnDraw(CDC *pDC){};
#endif
};


I was getting C2535 errors, when trying to pre-declare the method to be able to use it later in the class: Compiler Error C2535[1]

Or is there a better solution? Does anyone know how to pre-declare the function within a class so that it can be used directly, like pre-declaration is done with C?
Posted
Updated 24-Jan-16 2:10am
v4
Comments
nv3 24-Jan-16 6:04am    
Obviously you also have a definition of the CCDCDirectControls constructor in file bmpLoadView.cpp.
StephenJElliott 24-Jan-16 6:29am    
The only reference was the inclusion of the header file; but you are right. If I removed the include statement then the error went away with the original version; the problem with making a declaration in the header file, is that if the header file is referenced elsewhere, then it becomes a double declaration!
Richard MacCutchan 24-Jan-16 8:00am    
No, it must be something else, since the error was found by the linker, meaning that you had defined the constructor in two modules.
Kornfeld Eliyahu Peter 24-Jan-16 6:05am    
Where is bmpLoadView came from? Show the code of it!
StephenJElliott 24-Jan-16 6:36am    
That was the problem - there was an include statement in the code, that referenced the header, double declaring the variable. The other code must not have actually gotten compiled (test code) or something like that, kind of odd; in any case, it is actually a handy catch. I can code everything and then only move it over to the cpp file once done, commenting it out then.

I think you are confusing a few things here.

Declaration

In a declaration you just tell the compiler what the data type of a member, variable or function is, or which members and functions a class consists of. For example:

C++
int i;
void MyFunction (int i, double d);

class X
{
   X();
};


Declarations normally go into your .h (header) file or the .cpp file if they are just local to that file. You can include that .h file from as many .cpp files as you like. In fact you have to include in every .cpp file in which you use those definitions.

If you put a guard symbol around the entire .h file contents you can even include it multiple time from the same .cpp files (which sometimes happens in complex projects when certain headers include other headers):
C++
#ifndef _MYSOANDSOCLASS_H_
#define _MYSOANDSOCLASS_H_

... here goes the contents of the header file

#endif

So that is an important technique to get acquainted with.

Definition

In a definition you tell the compiler to produce code or data entries. For example:
C++
int numOfTableEntries = 0;

void MyFunction (int i, double d)
{
   ... some code here ...   
}

X::X()
{
  m_myMemberVariable = 5;
}


Definitions go into the .cpp; with one exception: Inline function definitions can be placed in the header file and the compiler/linker couple "mysteriously" take care that this doesn't lead multiple definitions, even if that header file is included multiple times.

So, in other words: Never place definitions -- i.e. executable code -- in a header file, except inline function definitions!

In your case, the file bmpLoadView when compiled seems to produce a definition for the CCDCDirectControls::CCDCDirectControls(void) function. And the linker now find two such definitions, one produced by your CDCDirectControls file and one by bmpLoadView. So take a look at what bmpLoadView.cpp contains and what it includes. Somewhere must be a definition of CCDCDirectControls::CCDCDirectControls(void) which doesn't belong there.

As for your amendment of the question:

Don't use the guard-symbol technique inside a class. That is very confusing and unnecessary.

Why do you want to pre-declare testmethod1? Please show the code that would require that. If you want to use testmethod1 in inline code that comes before the inline definition of testmethod1 that should be fine even without a pre-declaration.
 
Share this answer
 
v2
Comments
Richard MacCutchan 24-Jan-16 12:29pm    
I always understood that the definition was the first bit, and the declaration the part with the code inside. But I never found a convincing description of the two parts.
nv3 24-Jan-16 13:05pm    
You certainly meant the other way around, did you.
StephenJElliott 25-Jan-16 3:38am    
I like your solution ... except that I am unable to edit the "<h1>ifndef _MYSOANDSOCLASS_H_"; I am not sure why it is showing <h1> instead of #; please update your solution. For now I am coding everything in the .h file which I do not call from anywhere else. And then after that all compiles fine, I can move the declarations over to the cpp file. If I left declarations in the .h file, then when the compiler includes the .h file, the declaration would be made twice resulting in an error (because an object can only be declared once). However, to just get them drafted, everything is in one place to start with which is nice in terms of the programming process.
nv3 25-Jan-16 5:03am    
Yes, this is strange. I think the problem with the hash character not showing correctly might be a problem of the codeproject site. It showed the correctly in preview, but then messed it up on the final page. -- By just putting a space in front of the # I could "convince" it to do it correctly.
You have identical sample code at 2 locations for both the header and the source file. You should read your question slowly and double-verify it.

Essentially, if a function is declared in the header file, it should either be defined inline or after the class with the inline keyword (and it should be short). If the function is defined in the source file, it should typically not be inline and it might be longer.

Since you are using Visual Studio, you can use #pragma once to ensure that your class is used only once. If you use #ifndef/#define/#endif, then put them at the correct location. Essentially, it should generally surround the whole file. That is #ifndef/#define should be the first 2 lines of code and the #endif should be the last line of code in the file. Otherwise, you get 2 different definition of the class.

By the way, that kind of things works as expected for at least 15 years if not 20 or more. Since C does not have classes, you cannot compare with C rules as the comparison is unfair. You would have to compare free functions...

By the way, even in C, you won't put a function definition in an header to avoid linker duplication errors. In C++ you can see only one class definition per source file you compile (and that definition should match the definition as seen by other source file). Thus as soon as some file can be directly and indirectly included, you have the risk to see a definition multiple times. Thus a reason why you should uses guards.

Finally, a good habit is to always include the matching header first (except for the possible inclusion of a precompiled header file) in the source file. This will help you ensure that the header file is self-dependent (that is, the file will properly compile when included alone),
 
Share this answer
 
Comments
nv3 26-Jan-16 5:35am    
Many good points, Philippe!
StephenJElliott 3-Feb-16 5:11am    
Just one point: the .cpp and .h files are generally separated because the .h file is called over and over to reference the class methods and so forth while the implementation is only permitted generally once (and hence there is only one .cpp file that compiles once). However, there are inline functions that can be put in the header and these somehow compile properly (I use this for do-nothing code or if the code itself makes it clearer what is going on - where the implementation details actually matter).

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900