|
Take a look at CMainFrame's constructor. Is there an infinite loop?
Ryan "Punctuality is only a virtue for those who aren't smart enough to think of good excuses for being late" John Nichol "Point Of Impact"
|
|
|
|
|
I've got a bit of trouble figuring out the proper way to include classes and headers. Now as I've always been taught, you should type out a class declaration in a header file and leave the definition for the cpp file. Then when that's completed, you should only #include header files. That's the "etiquette" I've been taught anyway so that's what I'm employing here. Though I'm beginning to think some of my professors who cling to that are rather daft.
Now on to the problem. I have Class A that is required for Class B. Now Classes C and D both require Class B. Class E requires Classes A and C. Finally Class F requires D and E. Lost you yet? Maybe this will help:
Class A
/ \
Class B \
| \ \
Cls D Cls C |
| \ |
\ Class E
\ /
Class F
Now each individual cpp compiles lovely, the problem comes when linking. The errors always point to Class A so I'm pretty sure that it's getting included twice somehow. I'm using blocks like this at all include points, on cpp and h files, to try to keep something from including twice:
#ifndef CLASS_A_INC<br />
#define CLASS_A_INC<br />
#include "CLASS_A.h"<br />
#endif
Despite all this I can't get the linking errors to go away. Help please?
The question "Do computers think?" is the same as "Can submarines swim?"
Signature Red Studios
Jeryth
|
|
|
|
|
At the top of each .h file should be something along the lines of:
#if !defined(AFX_<code>filenamehere</code>_H__E944DC11_3852_4390_BA89_40C4B5867CB2__INCLUDED_)
#define AFX_<code>filenamehere</code>_H__E944DC11_3852_4390_BA89_40C4B5867CB2__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#endif
Jeryth wrote:
The question "Do computers think?" is the same as "Can submarines swim?"
The correct quote is from Dijkstra:
"The question of whether computers can think is like the question of whether submarines can swim."
"Opinions are neither right nor wrong. I cannot change your opinion. I can, however, change what influences your opinion." - David Crow
|
|
|
|
|
DavidCrow wrote:
The correct quote is from Dijkstra:
"The question of whether computers can think is like the question of whether submarines can swim."
I know where it comes from, I just didn't care to type the whole thing. But you're the first to recognize it, at least the first to comment.
Anyway, I didn't catch all that code you typed. Looked up the pragma pre-processor keyword and understand that coupled with the "once". That is I understand the point of it but not necessarily the implementation. Mind explaining it a bit?
I take it _MSC_VER is built in, correct? As for the defining tags, does that whole line of AFX_blah_blah_blah have to be there or can it be my own tag?
The question "Do computers think?" is the same as "Can submarines swim?"
Signature Red Studios
Jeryth
|
|
|
|
|
I might give a shot at an explanation.
#pragma once (according to MSDN) instructs the compiler to include the header file only once in the compilation. This works from VC++ version 4 (I'm not sure about this, but VC++6.0 has _MSC_VER=1200, so I guess 5.0 is 1100 and 4.0 is 1000). If you use VC++ 6.0 then _MSC_VER is 1200 and #pragma once should be sufficient for you. You just have to put #pragma once in ALL your header files (and only the header files).
All AppWizard-generated MFC projects come with header files that looks like this:
<br />
<br />
#if !defined(AFX_EX2_H__9190AD6B_F3D4_4DC8_B8DF_C4F8460B0306__INCLUDED_)<br />
#define AFX_EX2_H__9190AD6B_F3D4_4DC8_B8DF_C4F8460B0306__INCLUDED_<br />
<br />
#if _MSC_VER > 1000<br />
#pragma once<br />
#endif // _MSC_VER > 1000<br />
<br />
......<br />
<br />
#endif // !defined(AFX_EX2_H__9190AD6B_F3D4_4DC8_B8DF_C4F8460B0306__INCLUDED_)<br />
The #if - #define - #endif constructs implements the same idea as you do with your "own tags", but here the whole header file text is surrounded by the #if/#endif statements. I really can't see why that should be much different from putting #if/#endif around the #include statements instead, but maybe that's why it doesn't work for you. Anyway, as I see it the #if/#endif is redundant to #pragma once. In any event, the AFX_blah_blah_blah is just MFC's way of making a unique tag (AFX + filename + guid), if your tags are unique then they should work equally well.
Are you absolutely sure that your problems stems from multiple inclusions of the classA header? You can trace the parsing of your header files by putting a #pragma message (see MSDN) in the header file.
Cheers
Steen.
"To claim that computer games influence children is ridiculous. If Pacman had influenced children born in the 80'ies we would see a lot of youngsters running around in dark rooms eating pills while listening to monotonous music"
|
|
|
|
|
Steen Krogsgaard wrote:
Are you absolutely sure that your problems stems from multiple inclusions of the classA header?
I'll say I'm 95% sure that's the cause. All the linking errors mentioned Class A name in the error field. But now I have a new problem. I took Dave Crow's advice and redid my #ifndef statements. Now I'm testing in the class header file if an appropriate preprocessor tag has been defined, if not then it defines it and it continues to have the class declared. If it already has, it skips it. After the initial #ifndef I use separate ones to test for any required includes for that class. For example, Class A looks like this:
<br />
#ifndef CLASS_B_INC<br />
#define CLASS_B_INC<br />
#pragma once<br />
<br />
#ifndef CLASS_A_INC<br />
#include "CLASS_A.h"<br />
#endif<br />
<br />
<br />
#endif<br />
I think part of my problem was that I was possibly defining the pre-processor tags multiple times. This way, they only get defined in that class' header file. Note here that Class B won't try to define CLASS_A_INC ( that's left to Class A to do ) it will just include it and when that does Class A will define it on its own.
Now something like that written above is in all .h files. The .cpp files only have
<br />
#ifndef CLASS_A_INC<br />
#include "CLASS_A.h"<br />
#endif<br />
for their own classes, so above would be the Class A .cpp file. Now I'm getting errors that certain elements can't be found such as "cout : undeclared identifier" and "Class E : undeclared identifier" so some of my #include statements aren't being processed and I don't know why.
________________________________________________________________________
The question "Do computers think?" is the same as "Can submarines swim?"
Signature Red Studios
Jeryth
|
|
|
|
|
I would recommend that you *only* use the #ifndef/#define/#endif in the header file, and that you put only *one* construct for the entire file, as in
<br />
ifndef CLASS_B_INC<br />
#define CLASS_B_INC<br />
#pragma once<br />
<br />
#include "CLASS_A.h"<br />
<br />
<br />
#endif<br />
<br />
ifndef CLASS_A_INC<br />
#define CLASS_A_INC<br />
#pragma once<br />
<br />
class A : .....<br />
{<br />
...<br />
}<br />
#endif<br />
You don't need to put #ifndef/#endif around the #include statement in class_b.h. If class_a.h has already been parsed CLASS_A_INC will be defined and it won't be parsed again (it will be an empty file as the preprocessor will remove everything between #ifndef/#endif, and here that means everything in class_a.h), and you will effectively include an empty file. This, IMHO, is much cleaner than putting #ifndef/#endif around every single #include statement in your project.
Are you still sure that #pragma once does not solve your problem by itself, i.e. without all the #ifndef/#endif stuff? It does for me. I think MS put #if !defined/#endif for backwards-compatibility reasons (i.e. _MSC_VER <= 1000)
Cheers
Steen.
"To claim that computer games influence children is ridiculous. If Pacman had influenced children born in the 80'ies we would see a lot of youngsters running around in dark rooms eating pills while listening to monotonous music"
|
|
|
|
|
Okay so I changed those and it cleared up some of the mess. But the old errors came back. In the errors below, CABLE is what I've been referring to as Class A and TABLE is Class F, the bottom tier one.
error LNK2019: unresolved external symbol "public: __thiscall CABLE::~CABLE(void)" (??1CABLE@@QAE@XZ) referenced in function "public: __thiscall TABLE::TABLE(int)" (??0TABLE@@QAE@H@Z)
error LNK2019: unresolved external symbol "public: __thiscall CABLE::~CABLE(void)" (??1CABLE@@QAE@XZ) referenced in function __unwindfunclet$??0CARD@@QAE@XZ$0
Looks like it doens't know where to go for CABLE function calls. Any ideas?
________________________________________________________________________
The question "Do computers think?" is the same as "Can submarines swim?"
Signature Red Studios
Jeryth
|
|
|
|
|
Jeryth wrote:
Looks like it doens't know where to go for CABLE function calls
No, it looks like it doesn't know where to go for CABLE::~CABLE(void), i.e. the destructor of your CABLE class. Did you perhaps by any chance forgot to define it? It looks as it's declared in the class allright but not defined in a cpp file.
I wonder why you're calling CABLE::~CABLE in TABLE's constructor, looks to me as inefficient member variabel initialization
Cheers
Steen.
"To claim that computer games influence children is ridiculous. If Pacman had influenced children born in the 80'ies we would see a lot of youngsters running around in dark rooms eating pills while listening to monotonous music"
|
|
|
|
|
Yeah, saw the destructor reference and that was the first thing I checked before I posted. If only it would have been so easy. I'm not explicitly calling for any CABLEs to be made in the TABLE constructor. I'm creating some other objects that have CABLEs in them, but I'm pretty sure none of them are getting destroyed. I've got one implicit cast where I grab a line from cout and pass that into a function that's looking for a CABLE, so the VS is just doing that on its own. Don't know where the problem might be coming from.
________________________________________________________________________
The question "Do computers think?" is the same as "Can submarines swim?"
Signature Red Studios
Jeryth
|
|
|
|
|
Of course I didn't mean to imply that you would make such an elementary error , but there's no question (at least in my mind ) that the linker can't find the implementation of CABLE::~CABLE, so something's gotta be wrong. You could try to put {} after the declaration in header file to make ~CABLE inline, that way you're sure it's defined:
<br />
class CABLE<br />
{<br />
public:<br />
virtual ~CABLE() {};<br />
}<br />
If that gets rid of the linker error then recheck the definition of ~CABLE in your code.
Regarding calling of the constructor, it's called when temporary CABLE objects are constructed and destructed, for example during an assignment. Furthermore, the second linker error indicates that the destructor is called from a structured exception handler (the "_unwindfunclet" part sounds like stack unwinding to me)
Perhaps you could post some code to show the declaration and implemenations, or is it too large chunks?
cheers
Steen (from my home computer)
|
|
|
|
|
No, no, I've been known to make basic mistakes. Nearly tore all my hair out after typing 50 pages of code and couldn't get it to compile. Then found a missing semicolon about 20 lines up from where the compiler had flagged the error.
No, found out the problem. I had CABLE files in a different directory ( I wanted to keep them in a generic use folder ) and had added that directory to the project include folders, but had not added the files themselves to the project. Now compiling and linking is fine, but I've got yet ANOTHER problem.
I run the program in the debugger and after I get through a few menus, I get this:
DAMAGE: before Normal block ( #92 ) at ( 0x00323798 )
In stepping back through the debugger, it hilights the CABLE destructor. In particular, the line
<br />
delete [] cable;<br />
The cable var is a char * array so I don't know why it wouldn't be able to delete it. Any ideas here?
________________________________________________________________________
The question "Do computers think?" is the same as "Can submarines swim?"
Signature Red Studios
Jeryth
|
|
|
|
|
I think you made a memory overwrite somewhere in your code. MFC new puts guard bytes around your allocated block and checks if something has screwed up your block everytime you call new or delete - that's why you get the message in the destructor, as that's probably the first time after the error occurred that new or delete gets called. Alas, it has nothing to do with the destructor or the delete[] call as such. See this[^] MSDN article for more info.
Recheck your code for places where you use strcpy or similar function without checking the length of the arguments, especially your cable variable. Use strncpy instead.
Cheers
Steen
|
|
|
|
|
Hmm, I didn't make this an MFC project per se, just started with an empty solution but I guess some MFC is still being put it automatically.
That link was rather helpful, shows the same error message I'm getting so that should be the right track. I'm not using strcpy or strncpy anywhere. I use my own loops to copy element by element in CABLE. In fact the only string function I think I'm using is strlen . Here's the CABLE class in it's entirty. It's pretty simplistic, I'm pretty much just doing it for practice with plans to add on to it as I learn more.
#include <CABLE.h>
CABLE::CABLE()
{
cable = new char[1];
cable[0] = '\0';
length = 0;
}
CABLE::CABLE( int newLength )
{
cable = new char[newLength+1];
length = newLength;
for( int i = 0; i <= length; ++i )
{
cable[i] = '\0';
}
}
CABLE::CABLE( const char * const newCable )
{
length = strlen( newCable );
cable = new char [length+1];
for( int i = 0; i <= length; ++i )
{
cable[i] = newCable[i];
}
cable[length] = '\0';
}
CABLE::CABLE( const CABLE & rhs )
{
length = rhs.GetLength();
cable = new char[length+1];
for( int i = 0; i <= length; ++i )
{
cable[i] = rhs[i];
}
cable[length] = '\0';
}
CABLE::~CABLE()
{
delete cable;
cable = NULL;
length = 0;
}
CABLE & CABLE::operator=( const CABLE & rhs )
{
if ( this != &rhs )
{
delete [] cable;
length = rhs.GetLength();
cable = new char[length+1];
for( int i = 0; i <= length; ++i )
{
cable[i] = rhs[i];
}
cable[length] = '\0';
}
return *this;
}
char & CABLE::operator[]( int offset )
{
if ( offset > length )
{
return cable[length-1];
}
else
{
return cable[offset];
}
}
char CABLE::operator[]( int offset ) const
{
if ( offset > length )
{
return cable[length-1];
}
else
{
return cable[offset];
}
}
CABLE CABLE::operator+( const CABLE & rhs )
{
int totalLength = length + rhs.GetLength();
CABLE temp( totalLength );
for( int i = 0; i < length; ++i )
{
temp[i] = cable[i];
}
for( int j = 0; j < rhs.GetLength(); ++j, ++i )
{
temp[i] = rhs[j];
}
temp[totalLength] = '\0';
return temp;
}
void CABLE::operator+=( const CABLE & rhs )
{
int totalLength = length + rhs.GetLength();
CABLE temp( totalLength );
for( int i = 0; i < length; ++i )
{
temp[i] = cable[i];
}
for( int j = 0; j < rhs.GetLength(); ++j, ++i )
{
temp[i] = rhs[j];
}
temp[totalLength] = '\0';
*this = temp;
}
bool CABLE::operator==( const CABLE & rhs ) const
{
if ( length != rhs.length )
return false;
for( int i = 0; i < length; ++i )
{
if ( cable[i] != rhs.cable[i] )
return false;
}
return true;
}
const char * CABLE::GetCable() const
{
return cable;
}
int CABLE::GetLength() const
{
return length;
}
So as it is, I'm barely using the string class at all. It'd almost be worth it to swap out the strlen for a sizeof() call / size of a char .
________________________________________________________________________
The question "Do computers think?" is the same as "Can submarines swim?"
Signature Red Studios
Jeryth
|
|
|
|
|
If it's not an MFC App Wizard generated project you shouldn't have any MFC.
The only thing I can see in your code is that you use delete cable instead of delete[] cable in the destructor, but from your previous post I guess that's a typo (you said earlier that the debugger highlighted delete[] cable in the destructor).
How is CABLE used in your code? Which methods are called? That may give some clues.
Cheers
Steen
|
|
|
|
|
Jeryth wrote:
I'll say I'm 95% sure that's the cause. All the linking errors mentioned Class A name in the error field.
Multilple includes will give compiler errors(error C2011: 'CClassA' : 'class' type redefinition), not linking errors!
Cheers
Steen.
"To claim that computer games influence children is ridiculous. If Pacman had influenced children born in the 80'ies we would see a lot of youngsters running around in dark rooms eating pills while listening to monotonous music"
|
|
|
|
|
You're right, I mis-labeled my problem. All classes compiled fine, they just wouldn't link. It was complaining about resolving an exxternal link error or somthing along those lines.
________________________________________________________________________
The question "Do computers think?" is the same as "Can submarines swim?"
Signature Red Studios
Jeryth
|
|
|
|
|
Im using win32 c++ compiler, but now i want to run/execute my program using command line arguments. How do i go about it?
oam
|
|
|
|
|
Are you wanting to do so from within the IDE?
"Opinions are neither right nor wrong. I cannot change your opinion. I can, however, change what influences your opinion." - David Crow
|
|
|
|
|
Im using DOS, but now im used to execute it in the application
oam
|
|
|
|
|
From a command prompt (not DOS), type the name of your program followed by any command-line parameters that it supports.
"Opinions are neither right nor wrong. I cannot change your opinion. I can, however, change what influences your opinion." - David Crow
|
|
|
|
|
But then it just opens the program even though i supplied parameters
oam
|
|
|
|
|
Which means you aren't doing anything with them. Look at:
GetCommandLine()
__argc/__argv
CWinApp::m_lpCmdLine (MFC)
"Opinions are neither right nor wrong. I cannot change your opinion. I can, however, change what influences your opinion." - David Crow
|
|
|
|
|
I've been having network problems!
Anyway i'm able to run it from Debug folder
like F:\Debug>filename file1 file2
can you run this code from the command line
<br />
#include <windows.h><br />
#include <stdio.h><br />
<br />
void main( VOID )<br />
{<br />
STARTUPINFO si;<br />
PROCESS_INFORMATION pi;<br />
<br />
ZeroMemory( &si, sizeof(si) );<br />
si.cb = sizeof(si);<br />
ZeroMemory( &pi, sizeof(pi) );<br />
<br />
if( !CreateProcess( NULL,
TEXT("MyChildProcess"),
NULL,
NULL,
FALSE,
0,
NULL,
NULL,
&si,
&pi )
) <br />
{<br />
printf( "CreateProcess failed (%d).\n", GetLastError() );<br />
return;<br />
}<br />
<br />
WaitForSingleObject( pi.hProcess, INFINITE );<br />
<br />
CloseHandle( pi.hProcess );<br />
CloseHandle( pi.hThread );<br />
}<br />
|
|
|
|
|
mpapeo wrote:
can you run this code from the command line
Yes, why?
"Opinions are neither right nor wrong. I cannot change your opinion. I can, however, change what influences your opinion." - David Crow
|
|
|
|