Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

VC++ .NET syntax question

Status
Not open for further replies.

odlumb

Technical User
Oct 22, 2003
8
US
This question makes me feel a little stupid, but after spending hours working without success and combing through two books on C++ I still don't have the answer. That's partly because I'm slow, partly because C++ itself is brain-damaged, and partly because Microsoft has added so many extensions to the language that I'm simply stupified. And remember, this is .NET managed code(forms), not unmanaged MFC stuff.

Here it is, stripped down to the smallest and simplest file I can make and still demonstrate the problem.

//---------------------------------------------------------
namespace SomeNamespace
{
using namespace System;
using namespace System::ComponentModel;
using namespace System::Collections;
using namespace System::Windows::Forms;
using namespace System::Data;
using namespace System::Drawing;

public __gc class YYY; //forward reference, adequate for declarations but not constructors

public __gc class XXX : public System::Windows::Forms::Form
{
public: XXX(void) //constructor
{
this->stupid = new YYY();

//error C2512: 'SomeNamespace::YYY' : no appropriate default constructor available

}
private: SomeNamespace::YYY *stupid;
};

public __gc class YYY : public System::Windows::Forms::IMessageFilter
{
public: YYY(void) //constructor
{
this->dumb = new XXX();
}
public: SomeNamespace::XXX *dumb;
};
}
//---------------------------------------------------------

What we have here are two objects in the same namespace referencing one another. What I can't figure out is why class XXX thinks there is no constructor for class YYY. This must have something to do with forward referencing, because class YYY has no problem finding the constructor for class XXX. I suspect that my "forward reference" line near the top of the file needs some additional info, but I have no idea what it's missing (if in fact that's the problem). What do I need to add to this file so the compiler knows about YYY's constructor?

Thanks for your help! ;-)
 
It's not managed/unmanaged problem: it's an ordinal C++ issue. You have only forward class YYY declaration in the point with new YYY op: it's not enough. You may declare pointers/references to forward declared classes, because of no need to know anything about class members in that case. If you want to create a new object of the class, present at least this class constructor declaration before this point.

The C++ compiler (not only VC++) does not know what to do with undeclared class YYY new op...
 
ArkM,

Thanks. I already assumed that I had insufficient "forward reference" information. But, how does one do this? Can you give me an example of how I can supply forward reference info about a class's constructor? It's literally the syntax about which I'm clueless, not the concept. I can find no examples in my books, or in the many code examples I have perused on the web. Use my example. What's missing?

Thanks!
 
Common way to go in that case: split declarations and definitions. No such animal as a forward member declaration in C++ (a forward declaration is an incomplete declaration - this name is a class/structure name, that's all). Present full class declaration (with member functions signatures w/o bodies), place it in a header file. Now you may use all this class members after #include this file. Place this class definition (or implementation: member functions bodies) in a separate cpp file.

Let's think about this program case. We (or C++ compiler;) know the name of the entity only (forward declaration). We don't know anything about this class members (constructors are class members;). May be it's a class w/o default constructor (it's a possible case). We must compile operator new call - allocate sizeof(class) bytes then call a proper constructor. How many bytes? We don't know. What's this class public constructor? We don't know. The only way: emit error message...

More specific way to build a code with high degree of modularization: use abstract classes with so called class factories (static members to create concrete child class objects behind the scenes). But it's another story...
 
Oh, second helping: it's not a syntax problem, it's semantics...
 
ArkM,

I really appreciate all your help. You obviously know a lot about C++. Unfortunately, I’m going to stick to my original assertion that this is a VC++ .NET Forms app related problem.

Your recommendation to use separate .h and .cpp files is the conventional C++ approach. But conventional C++ doesn’t put all the executable code in a .h file (not a .cpp file), as the VC++ .NET IDE always does when building a .NET Forms app. Conventional C++ doesn’t have “namespace” as a key word, which opens up a bunch of questions such as:

1. Should .h files for class declarations be wrapped in a designated namespace?
2. If not, should they be included inside or outside of the namespace brackets in the file in which they are included?
3. If there are cross-referenced declarations (i.e., class X references class Y and class Y references class X) should the .h file be included at the top of the file or at the end?

I have built other C++ (not VC++ .NET) applications before, and never had a problem writing class definitions in a code file (.cpp) and class declarations in a header file (.h) and getting it all working. I have spent many hours trying every conceivable combination I can think of attempting to get this to work in VC++ .NET using Forms. Nothing I have tried has been successful. Since I have to believe that this can be done, I maintain it is simply a matter of knowing the “secret formula”, i.e., the syntax, that MS intended to be used when compiling code with cross referenced class definitions.

So although I appreciate you help a great deal, I’m afraid that until somebody who has actually solved this problem in VC++ .NET can show be an actual example (in code), my project remains at a standstill. I continue to experiment, and I continue to search through dozens of example project I have found on the web, but so far I have not found an appropriate (parallel) example, and I have not found a solution ;-(
 
After several days work, I crawled my way to the solution. Here is the magic incantation, using abstracted and abbreviated files. This particular example has everything in the same namespace. That’s not absolutely necessary, and the way to put different classes which reference one another in different namespaces should be “decipherable” from my example. Warning : MS reports possible compiler bugs if you use different namespaces. That being said, here is the solution:

ClassY.h ---------------------------------------------
Code:
#pragma once

namespace SomeNamespace
{
public __gc class X;

public __gc class Y : public System::Windows::Forms::Something
	{
	public: SomeNamespace::X *parent;
	public: Y(void); //constructor #1
	public: Y(SomeNamespace::X *sender); //constructor #2
	public: void setParent(SomeNamespace::X *sender);
	};
}
ClassY.cpp---------------------------------------------
Code:
#pragma once

#include "ClassX.h"

namespace SomeNamespace
{
public __gc class Y : public System::Windows::Forms::Something
	{
	public: SomeNamespace::X *sibling; //member of type class X

	public: Y(void) //constructor #1
		{
		//code body
		}

	public: Y(SomeNamespace::X *sender) //constructor #2
		{
		//code body
		}

	public: void setSibling(SomeNamespace::X *sender)
		{
		//code body
		}
	};
}
ClassX.h---------------------------------------------
Code:
#pragma once

namespace SomeNamespace
{
	using namespace System;
	using namespace etc., etc…

	public __gc class X : public System::Windows::Forms::Form
	{
	public: SomeNamespace::Y *sibling; // member of type class Y

	public: X(void); //constructor

	public: void setSibling(SomeNamespace::Y *sender);
	};
}
ClassX.cpp---------------------------------------------
Code:
#pragma once

#include “ClassY.h”

namespace SomeNamespace
{
public __gc class X : public System::Windows::Forms::Something
	{
	public: SomeNamespace::Y *sibling; //member of type class Y

	public: X(void)
		{
		//code body
		}

	public: void setSibling(SomeNamespace::Y *sender)
		{
		//code body
		}
	};
}
All this seems a bit obvious once you have it figured out. The mental “obstacle” that kept me from finding the solution for so long was the fact that when using .NET Forms, the IDE puts all the executable code in a .h file (default name – Form1.h). One can’t use this file as the header file to be included in the sibling class’s .cpp file. I had to duplicate Form1.h, rename it, strip out all the code bodies and add semicolons to the end of all the declaration to produce a real working header file. This new file can then be included in the sibling class to resolve all the crossed forward references. Since my original Form1.h had grown to 4500 LOC, this was a fairly tedious (albeit mechanical) process.

Thanks everyone for your patience and putting up with my stupidity ;-)
 
Oops! The line:

public __gc class Y;

should be included in file ClassX.h, like this:

Code:
#pragma once

public __gc class Y;

namespace SomeNamespace
{
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top