Okay, so I'm running into trouble with Forward Declarations in Visual Studios C++ (C++/CLI).
The code is as follows:
A.h
#include "B.h"
#ifdef B_H
#pragma once
public ref class A : public base_class //base_class is public, memory managed
{
B^ b;
}
#endif
B.h
#define B_H
#pragma once
ref class A;
ref class B
{
A^ a;
}
#include "A.h"
The #ifdef/#pragma guards should keep be keeping a *.h from being read twice, and forcing b.h to be read first, and from the compiler output I'm pretty sure they are. (I'm not even sure the #ifdef/#define is needed with the #pragma once and #include placement)
But, the complier complains of a path/a.h: error C2011: 'class' type redefinition.
See file path/B.h
Should I be doing something with the forward declaration of A because it's a derivative class in the actual class definition, or am I barking up the wrong tree?
Two changes needed:
Add semicolons after the closing brace of the class definitions.
In A.h, move the #pragma once to be the very first line in the file. It's getting screwed up by having this inside the #ifdef block.
Also, note that a simpler way to do this would be to not have either header file include the other, and use forward declarations in both files:
A.h:
#pragma once
ref class B;
public ref class A : public base_class //base_class is public, memory managed
{
B^ b;
};
B.h
#pragma once
ref class A;
ref class B
{
A^ a;
};
Related
so somewhere along the lines of putting this app together I've started to get a runtime check failure stack corruption when the destructor for a cstring class member is called.
I've gotten to the point of trying to debug this by throwing bricks at the issue but still havent root caused it. At the current moment the class that the cstring resides in does nothing but initialize its private string members and set a pointer to another class to NULL.
Interestingly if I do not set the class pointer to NULL and comment out that line the corruption goes away. I think this is somewhat of a red herring, and that something is changing in the way the compiler is putting the code together when it pulls in the .h file that contains theCLog definitions and that would be used since I'm declaring a pointer to that object.
int _tmain(int argc, _TCHAR* argv[])
{
DWORD a = 0xBABA; //just to help catch the corrupter
DWORD b = 0xDFDF;
CStringW startat = L"\\\\anetworkshare\\fre";
CStringW lookfor = L".inf";
DirEnum myEnum(startat,lookfor);
ULONG en = a + b;
en = a - b;
return 0;
}
DirEnum.cpp
DirEnum::DirEnum(CString startingdir,CString fileFilter)
{
m_plogfile = NULL; //If you comment out this line corruption goes away
m_startingdir = L"";
m_extfilter = L"";
if(startingdir.GetLength() > 0)
m_startingdir = startingdir;
if(fileFilter.GetLength() > 0)
m_extfilter = fileFilter;
//following commented out to tshoot
//CLogBase& ref = ref.GetInstance();
//logBase = &ref;
//m_plogfile = new CLog(L"DirEnumerator",L"logfile.txt",logINFO);
}
Now I suspect that something in the log.h file is causing a change to occuur in the ATL or CString libraries but I dont know what. Heres the log.h file
#pragma once
//#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit
#ifndef UNICODE
#define UNICODE
#endif
#ifndef _UNICODE
#define _UNICODE
#endif
using namespace std;
#ifndef TYPEDEF_H
#define TYPEDEF_H
#include <string>
#include <sstream>
#include <iostream>
#include <fstream>
#include <tchar.h>
#include <time.h>
//simple defines to allow the TCHAR library to be used
typedef std::basic_string<TCHAR> tstring;
typedef std::basic_ostream<TCHAR> tostream;
typedef std::basic_istream<TCHAR> tistream;
typedef std::basic_ostringstream<TCHAR> tostringstream;
typedef std::basic_istringstream<TCHAR> tistringstream;
typedef std::basic_ofstream<TCHAR> tofstream;
#if defined(UNICODE) || defined(_UNICODE)
#define tcout std::wcout
#define tcin std::wcin
#else
#define tcout std::cout
#define tcin std::cin;
#endif
#endif
#if defined DEBUG || defined (_DEBUG)
#define TOCONSOLE
#endif
typedef enum LOGLVL{logERROR =0,logWARN,logINFO,logDEBUG};
//CLogBase os a singleton log class. Intent is that you can establish a reference from anywhere in the project and write to the same file
// without having locking issues or threading issues
class CLogBase
{
public:
static CLogBase& GetInstance(CString logname = L"log.txt",LOGLVL lvl = logWARN);
~CLogBase(void);
tostringstream& GetLog(LOGLVL level);
tostringstream& GetStream(LOGLVL);
void Forceflush();
private:
CLogBase(CString file,LOGLVL lvl);
//our outstream
tostringstream m_os;
tostringstream m_dummy;
tofstream m_filestream;
CString m_filename;
LOGLVL m_reportlvl;
//Private declarations to prevent copy constructors from being invoked; these are do nothig implimentations
CLogBase(CLogBase const&);
void operator=(CLogBase const&);
};
class CLog
{
public:
CLog(CString component);
CLog(CString component,CString logname,LOGLVL lvl);
~CLog();
void Log(LOGLVL,CString message);
void CLog::Flush();
tostringstream& CLog::GetStream(LOGLVL lvl);
private:
CString m_componentname;
CLogBase* m_logBase;
};
I thought I would answer this as I found the issue. this was not a coding problem per se but a visual studio issue.
What happened was that I was storing the direnum.h file and .cpp file in a different directory than the one used for the main project. referencing the header with #include "..\somedir\direnum.h"
at one point in time visual studio reported the file as locked and did I want to overwrite \ cancel etc. I choose overwrite but what seemed to happen was that this caused VS to COPY the files to the current project. All my troubleshooting attempts were being edited in the local somename.h file whtne opened in the editor but the compiler was doing the correct thing and pulling down the .h file from the location above.
removing switching to the now local copy of direnum.h and recompiling fixed this as it was compiling part of the code as ANSI and the other part as WCHAR
why would the following sniplet
#include <atlcom.h>
...
class FormRegionWrapper;
...
// Errorsource :
typedef IDispEventSimpleImpl
<2, FormRegionWrapper, &__uuidof(FormRegionEvents)>
FormRegionEventSink;
will give me the following errors:
// Error ouput:
error C2143: syntax error : missing ';' before '<'
error C4430: missing type specifier - int assumed.
Note: C++ does not support default-int
?!?
(The sniplet is taken from here : Building a C++ Add-in for Outlook 2010 ). My environment : MS Visual Studio 2012 Professinal, and Windows 7-64.
PS 1: Here what the help says about the IDispEventSimpleImpl :
// Help IDispEventSimpleImpl Class : This class provides implementations of
// the IDispatch methods, without getting type information from a type library.
// template <
// UINT nID,
// class T,
// const IID* pdiid
// >
// class ATL_NO_VTABLE IDispEventSimpleImpl :
// public _IDispEventLocator<nID, pdiid>
//
// Requirements
// -------------------
// Header: atlcom.h
Have you included atlcom.h so that the template IDispEventSimpleImpl is defined? Are the declarations of other classes (I assume written by you) used in the template declaration available? And i don't think that forward definition of FormRegionWrapper is enough, can you try and include the declaration of that class, so that template sees it?
UPDATE
Not sure if this will help much, but I replaced the source of FormRegionWrapper.h with the colde below (example from the MSDN page on IDispEventSimpleImpl:
#pragma once
#include "stdafx.h"
#include <vector>
#include <algorithm>
_ATL_FUNC_INFO Event1Info1 = { CC_CDECL, VT_EMPTY, 1, { VT_I4 } };
class CEventHandler;
typedef IDispEventSimpleImpl <1234, CEventHandler, &__uuidof(IDispatch)>
DummySink;
class CEventHandler : public DummySink
{
public:
BEGIN_SINK_MAP(CEventHandler)
SINK_ENTRY_INFO(1234, __uuidof(IDispatch), 1, OnEvent1, &Event1Info1)
END_SINK_MAP()
void __stdcall OnEvent1(LONG l)
{
//ATLASSERT(l == 445533);
if (l != 445533)
OutputDebugString(L"l is not 445533\n");
}
HRESULT Advise1234(IUnknown * punk) {
return IDispEventSimpleImpl<1234, CEventHandler, &__uuidof(IDispatch)>::DispEventAdvise(punk);
}
};
If this works, you can safely assume that the template is being included correctly.
Add this line after the #include directives in FormRegionWrapper.h:
using namespace ATL;
My simple class won't compile in Visual Studio. It worked before I added the string company member and the getter method getCo() to it. I think I need to put #include the string standard library somewhere but I am not sure where. Any idea where? In my header file, I have:
#pragma once
#ifndef ENGINEER_H_
#define ENGINEER_H_
class engineer {
int years;
string company;
public:
engineer(int years);
~engineer(void);
int getYears();
string getCo();
};
#endif ENGINEER_H_
And in my CPP file for the definition of the class, I have:
#include "StdAfx.h"
#include "engineer.h"
engineer::engineer(int y, string c){
years = y;
company = c;
}
engineer::~engineer(void) {
}
int engineer::getYears() {
return years;
}
string engineer::getCo() {
return company;
}
Put it in the header file, and prefix your usage of string with the namespace std.
Header:
#include <string>
class engineer
{
std::string company;
};
In the implementation file (.cpp) you can prefix the names or have a using directive.
Implementation:
using namespace std; // using directive, no longer need to use std::
Avoid putting the using directive in a header file, as that pollutes the global namespace and can cause problems with naming collisions in other libraries you may wish to use.
Put it in the header file, after the include guards:
#include <string>
using std::string;
This way, it will also be available for your cpp file, and you don't have to include it again.
BTW, the #pragma once and #ifndef ENGINEER_H_ serve the same purpose. You can have only one of them. Code generated by VC use the #pragma, which is shorter and doesn't add a definition, so that's what I'd use (no harm if you leave both, though).
I'm wondering if I can have two classes look like these:
//file: Small.h
#pragma once
#include "Little.h"
class Small :
public Little
{
public:
Small(void){}
~Small(void){}
};
and
//file: Little.h
#pragma once
#include <iostream>
#include "Small.h"
using namespace std;
//class Small;
class Little
{
public:
Little(){ s = 0; }
void print(){ cout << "oops!" << endl; }
Small* s;
};
And now my problem: When I wanna create an object of type "Small" and call its "print()" function, VS-2010 says that "class 'Small' has no member named 'print()'." What's the solution?
The following should work, however, you should be constructing classes in this manner, the base class should really have a member of the type of a derived class.
However as the member is just a pointer, the code should still compile and work, however your asking for errors.
The problem with you code is that the class Small must be defined before you create the class Little and Little bfroe you create Small
You Should do it in one file as follows, as they are interdependent
//file: SmallLittle.h
#pragma once
#include <iostream>
using namespace std;
class Small;
class Little
{
public:
Little(){ s = 0; }
void print(){ cout << "oops!" << endl; }
Small* s;
};
class Small :
public Little
{
public:
Small(void){}
~Small(void){}
};
However since Small is a member type of Little, your probably better of creating a single class as follows, The only reason for using your code is so you can use Little code in which Small is not defined, or used. However in this case your better off using a void * type for the pointer.
as Follows
//file: Small.h
#pragma once
#include <iostream>
using namespace std;
class Small;
class Small
{
public:
Small(){ s = 0; }
void print(){ cout << "oops!" << endl; }
Small* s;
~Small(void){}
};
Also you I don't think you need to set s to 0, as this is NULL, which should be the value until you create a pointer using new of assign a pointer.
I have a problem lunching a thread within a class A for example where the class A is a static member of class B with in a dll. I am using Visual Studio 9 and boost 1.40. Please consider the following code:
mylib.h:
#include <boost/thread.hpp>
#include <windows.h>
#ifdef FOO_STATIC
#define FOO_API
#else
#ifdef FOO_EXPORT
#define FOO_API __declspec(dllexport)
#else
#define FOO_API __declspec(dllimport)
#endif
#endif
class FOO_API foo{
boost::thread* thrd;
public:
foo();
~foo();
void do_work();
};
class FOO_API bar{
static foo f;
public:
static foo& instance();
};
mylib.cpp:
#include "mylib.h"
foo::foo()
{
thrd = new boost::thread(boost::bind(&foo::do_work,this));
}
foo::~foo(){
thrd->join();
delete thrd;
}
void foo::do_work(){
printf("doing some works\n");
}
foo& bar::instance(){return f;}
foo bar::f;
in the executable application, I have:
main.cpp:
#include "mylib.h"
void main(){
bar::instance();
}
If I link mylib statically to the executable app, It prints out "doing some works", while if I link it dynamically (dll), it does nothing.
I really appreciate any help.
Your program could be exiting before the thread completes. You might try waiting after the bar::instance() call, or joining the thread in main. Something else to try would be to flush stdout after the printf call.
From the MSDN documentation:
If your DLL is linked with the C
run-time library (CRT), the entry
point provided by the CRT calls the
constructors and destructors for
global and static C++ objects.
Therefore, these restrictions (*) for
DllMain also apply to constructors and
destructors and any code that is
called from them.
(*) The restrictions include communicating with threads.
It's best to make the global variable a pointer, and construct and release the object in dedicated callback routines.
See also this helpful SO answer.