Problem Initializing an Array in a Global Variables Header File C++ - c++

I'm writing a simple program using SDL, but I'm running into a strange problem. First the code:
#ifndef GLOBAL_VARIABLES_H
#define GLOBAL_VARIABLES_H
#include <string>
#include <cassert>
#include "SDL.h"
#include "SDL_image.h"
using std::string;
const int SCREEN_WIDTH = 800;
const int SCREEN_HEIGHT = 600;
const int SCREEN_BPP = 32;
const string MAIN_BACKGROUND_FILENAME = "tempBackground.jpg";
SDL_Rect CARD_CLIPS[2];
const int CARD_BACK = 0;
const int CARD_FRONT = 1;
CARD_CLIPS[CARD_BACK].h = 196;
CARD_CLIPS[CARD_BACK].w = 286/2;
CARD_CLIPS[CARD_BACK].x = 286/2;
CARD_CLIPS[CARD_BACK].y = 0;
CARD_CLIPS[CARD_FRONT].h = 196;
CARD_CLIPS[CARD_FRONT].w = 286/2;
CARD_CLIPS[CARD_FRONT].x = 0;
CARD_CLIPS[CARD_FRONT].y = 0;
#endif
The error I'm getting is this:
1>c:\users\--\global variables.h(23): error C2466: cannot allocate an array of constant size 0
1>c:\users\--\global variables.h(23): error C2143: syntax error : missing ';' before '.'
1>c:\users\--\global variables.h(23): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
1>c:\users\--\global variables.h(23): error C2371: 'CARD_CLIPS' : redefinition; different basic types
1>c:\users\--\global variables.h(18) : see declaration of 'CARD_CLIPS'
Repeat same error for each time I try to initialize an element of the SDL_Rect.
Note that the SDL part has nothing to do with the problem. If I try to declare an int array and initialize it in the same way, I get the exact same error. If I put any of this in my main.cpp it works completely fine.
Thanks for the help. Let me know if additional information is needed.
EDIT: Note that I get no errors except for when I try and use arrays in the header file. Though I do what to understand the conventional way to do things, I also want to understand why, from a fundamental standpoint, I can't declare and initialize arrays in a header file like this.

First, variable definitions shouldn't be in header files, only extern declarations.
Second, you can initialize variables (including arrays) in the definition, or assign the content as executable statements inside a function. You can't put executable statements at file scope.
Array initialization looks like this:
int a[4] = { 1, 4, 9, 16 };
not like this:
int a[4];
a[0] = 1; // ILLEGAL outside a function!
a[1] = 4;
a[2] = 9;
a[3] = 16;

This article might provide some guidelines on what should be included in a header file.
It says C in the title but of course it's applicable to C++.

As Ben Voigt has already explained, your problem has nothing to do with header files. It is simply that you have put ordinary executable statements that are not declarations, directly at namespace scope (that is, outside any function or class). You can't.
This statement is technically fine:
const int CARD_BACK = 0;
It's technically fine because it is a declaration. There is no assignment. The = here does not denote assignment, but is part of the declaration syntax, indicating that an initializer follows.
I say "technically" because you really should reserve ALL UPPERCASE names for macros, but the compiler doesn't care.
On the other hand, this statement is not OK at namespace scope:
CARD_CLIPS[CARD_BACK].h = 196;
That's because it's not a declaration, it is not introducing a new name: it's an assignment.
Oh, my eyes hurt from all that uppercase!
Cheers,

Related

How to fix redefinition error with constants in Header with Namespaces?

I'm a begginer with C++ and I'm trying to practice with headers and Namespaces. Specifically I wanted to create different modules with their own namespaces so I can use one program to go through others without mixing the names. I used the advice from this other question and it works fine with functions but when I get to a constant I get an "redefining error"
The 2 relevant files:
//mainHeader.h
#pragma once
#include <iostream>
#include <string>
#include <sstream>
namespace primes {
int isPrime(int a);
}
namespace CONST {
typedef unsigned long long int LONGINT;
double pi;
}
namespace E1 {
int main();
}
namespace E2 {
int main();
}
//CONSTANTS.cpp
#include "mainHeader.h"
namespace CONST{
pi = 3.14159265;
typedef unsigned long long int LONGINT;
}
Of course there's a main function that is mostly empty and 2 other .cpp files that are working fine. It compiled and worked as wanted before I created the CONSTANTS.cpp and decided to test the same for constants
The problem is that this code tells me that pi in CONSTANTS.cpp isn't defined correctly:
missing type specifier - int assumed. Note: C++ does not support default-int
However, if I add the type to the definition in CONSTANTS
it throws that redefine error.
> e1.obj : error LNK2005: "double CONST::pi" (?pi#CONST##3NA) already defined in CONSTANTS.obj
> e2.obj : error LNK2005: "double CONST::pi" (?pi#CONST##3NA) already defined in CONSTANTS.obj
> e3.obj : error LNK2005: "double CONST::pi" (?pi#CONST##3NA) already defined in CONSTANTS.obj
That sounds like the declaration in mainHeader.h is the problem but if I change it or take it out I get:
> ...\e3.cpp(34): error C2039: 'pi': is not a member of 'CONST'
> ...\mainHeader.h(12): note: see declaration of 'CONST'
> ...\e3.cpp(34): error C2065: 'pi': undeclared identifier
So I don't understand. If I take it out it doesn't find any definition, if I add it, it finds more than one.
The code for e1.cpp just in case, although I think the only problem would be the first line:
#include "mainHeader.h"
namespace E1 {
int main()
{
int ans = 0;
for (int i = 0; i < 1000; i++) {
if ((i % 3 == 0) || (i % 5 == 0)) ans += i;
}
std::cout << ans << std::endl;
return 0;
}
}
I tried what I think is every combination of definition and initialization. I used. I tried adding #pragma once to CONSTANTS.cpp, to e1.cpp, I even tried using
#ifndef CONST_H ... #endif
I added #include "mainHeader.h" to each eX.cpp file because there are functions that I want to share between them. Like for example primes.cpp will have some functions that some eX.cpp files will use, so I need to be able to call them.
Any help will be appreciated
Declare pi as const double and initialize it in header, or if you don't want to declare it as const really then prepend extern to declaration. If you don't do this still it will be extern, but it is also defined as 0.

expected constructor, destructor, or type conversion before string constant

I am only in the beginning steps of this program but I like to compile as I am making code. Also I am very new with ADTs so when making this code I ran into some problems that I have no idea what they mean.
Expression.h
#include "header.h" //Library that contains thing like iomanip, cstring, etc.
class Expression
{
private:
char *ieEXP; //Array of characters
char *peEXP; //Array of characters
const int MAX = 40; //Max size for the array
public:
//Initialize both arrays to 0
Expression(){ieEXP[MAX] = {0}, peEXP[MAX] = {0}};
Expression(const Expression &);
//Destroy contents within the array after program completes
~Expression(){ieEXP[MAX] = {0}, peEXP[MAX] = {0}};
//void ReadInFix(char *ieEXP);
//void PrintInFix(char *ieEXP);
//void StrCatch();
//bool IsOperator();
//void IntoPostFix(char *peEXP);
//void PrintPostFix(char *peEXP);
//int Priority();
};
Compilation
g++ -c Expression.h
This is the exact error that I get
Expression.h:1: error: expected constructor, destructor,
or type conversion before string constant
Also other methods have not been used yet simply just creating the class right now, and int main has not called anything yet.
Thank you.
The solution is probably to not compile a header file, as g++ doesn't recognize *.h as a source file. You probably want to create a .cpp file that includes your header, and compile that. g++ will recognize the .cpp and treat it properly.
Expression(){ieEXP[MAX] = {0}, peEXP[MAX] = {0}};
ieEXP and peEXP are pointers not arrays.

Class declaration in a header file and static variables

Noob question, but would like to understand the following:
Imagine I have a multifile project. I'm specifying a class in a header file to be shared among all the files in the project, and I write this : static int test = 0; and in the next line this: static const int MAX = 4;
The first one would be an error trying to compile because of the one definition rule. But the second one will compile without errors. Why?
From what I understand, both have the same properties: whole execution storage duration, class scope and no linkage.
Any help?
EDIT: testing an external constant declaration in a header: extern const int MAX = 4; to force external linkage produced the expected error. So I don't understand why with the variable it gives me the error and with the constant it doesn't.
Try
static const int test = 0;
I've sometimes noticed compiler errors with the immediate initialization of static const variables in the header file. You can always use the declaration in the header
class MyClass
{
// ...
static const int test;
// ...
}
and initialize it in the corresponding .cpp file
const int MyClass::test = 0;
This should work properly with any other types than int as well.
Integer constants in C++ don't actually occupy any space in the object and don't act like variables in general. Think about them more like numbers that are given names in this particular context.

Why won't this c++ code compile?

Seeig that i'm new to C++ I thought i'd try and write a very simple console app that populates a 2D-array and displays its contents.
But the code I've written won't compile.
Some of the errors I get are:
error C2065: 'box' : undeclared identifier
error C2228: left of '.GenerateBox' must have class/struct/union
Here is my code:
#include <iostream>
using namespace std;
int main()
{
Box box;
box.GenerateBox();
}
class Box
{
private:
static int const maxWidth = 135;
static int const maxHeight = 60;
char arrTest[maxWidth][maxHeight];
public:
void GenerateBox()
{
for (int i=0; i<maxHeight; i++)
for (int k=0; k<maxWidth; k++)
{
arrTest[i][k] = 'x';
}
for (int i=0; i<maxHeight; i++)
{
for (int k=0; k<maxWidth; k++)
{
cout << arrTest[i][k];
}
cout << "\n";
}
}
};
Any idea whats causing these errors?
The C++ compiler reads source files in a single pass, from top to bottom. You have described the Box class at the bottom, after main(), after the part where you attempt to use the class. Accordingly, when the compiler gets to the part where you say 'Box box;', it has not yet seen the class definition, and thus has no idea what 'Box' means.
Move the main function to the bottom of your code. Specifically, you need to define Box before you reference it.
The only time when you can get away with only a forward declaration (i.e. class Box;) is when you just use Box as a pointer or reference.
You have to define Box before using it. So for your small test you can put your class definition before the main.
For bigger programs, you will put your class definitions inside .h header files that you will include at the top of your source files.
Is due to pre declaration of main(). Use main after declaration of class Box.
#nikko is right. You have to declare the Box class before using it.By either cutting pasting the declarationor telling the compiler you will declare them later
try this
extern class Box;
//use box class here
//then define it later as you wish

Resolving "only static const integral data members can be initialized within a class" compilation error

The following for creating a Global Object is resulting in compilation errors.
#include "stdafx.h"
#include <iostream>
using namespace System;
using namespace std;
#pragma hdrstop
class Tester;
void input();
class Tester
{
static int number = 5;
public:
Tester(){};
~Tester(){};
void setNumber(int newNumber)
{
number = newNumber;
}
int getNumber()
{
return number;
}
}
Tester testerObject;
void main(void)
{
cout << "Welcome!" << endl;
while(1)
{
input();
}
}
void input()
{
int newNumber = 0;
cout << "The current number is " << testerObject.getNumber();
cout << "Change number to: ";
cin >> newNumber;
cout << endl;
testerObject.setNumber(newNumber);
cout << "The number has been changed to " << testerObject.getNumber() << endl;
}
Here are the compile errors:
1>------ Build started: Project: test, Configuration: Debug Win32 ------
1>Compiling...
1>test.cpp
1>.\test.cpp(15) : error C2864: 'Tester::number' : only static const integral data members can be initialized within a class
1>.\test.cpp(33) : error C2146: syntax error : missing ';' before identifier 'testerObject'
1>.\test.cpp(33) : error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
1>.\test.cpp(49) : error C2039: 'getNumber' : is not a member of 'System::Int32'
1> c:\windows\microsoft.net\framework\v2.0.50727\mscorlib.dll : see declaration of 'System::Int32'
1>.\test.cpp(55) : error C2039: 'setNumber' : is not a member of 'System::Int32'
1> c:\windows\microsoft.net\framework\v2.0.50727\mscorlib.dll : see declaration of 'System::Int32'
1>.\test.cpp(57) : error C2039: 'getNumber' : is not a member of 'System::Int32'
1> c:\windows\microsoft.net\framework\v2.0.50727\mscorlib.dll : see declaration of 'System::Int32'
1>Build log was saved at "file://c:\Users\Owner\Documents\Visual Studio 2008\Projects\test\test\Debug\BuildLog.htm"
1>test - 6 error(s), 0 warning(s)
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
How do I create a Global Class
Object correctly like I've attempted
here.
And how do I fix that "only static
const integral data members can be
initialized within a class"
And basically how do I fix the rest
of the errors so I can get this to
compile?
I like declaring Global Class Objects at file scope (I like declaring all globals at file scope) because when I have to create separate source files and do "extern" and everything it becomes extremely complicated and never works for me. Although, I do want to figure out how to do that eventually... it seems every tutorial I look at won't compile though and unless it compiles I have no idea how to recreate it!
If I can just get this to compile...then I can successfully learn how to do this. So if someone could rewrite the above to where it literally copies & pastes into Visual C++ Express 2008 and works I will finally be able to figure out how to recreate it. I'm extremely excited on seeing the fix for this! It is just I can't get Global Objects to work right! Any other information on declaring Global Class Objects...or anything for that matter is welcome!
Just start addressing the errors one by one. A lot of the errors are just cascaded from the initial errors, so it looks like there are a lot of problems when there's only a couple. Just start from the top:
1>.\test.cpp(15) : error C2864: 'Tester::number' : only static const integral data members can be initialized within a class
You can't initialize a member in the class definition unless it's static, const, and one of the integral types. Leave the "= 5" off of the declaration of number. Then you'll need to have a definition of Tester::number outside of the class definition, like so:
int Tester::number = 5;
Problem #2:
1>.\test.cpp(33) : error C2146: syntax error : missing ';' before identifier 'testerObject'
Almost exactly what it says (missing semi-colon errors can be a bit inexact in saying where the semicolon should be) - you need a semi-colon after the definition of the Tester class.
Fix those and your compilation problems go away.
The key thing is to try and take compiler errors one at a time from the top. If you get more than about 3 of them, you can probably just ignore everything after the 3rd or so because the initial error just cause the compile to into the weeds (and if they are real errors, they'll show up again in the next compile anyway).
Error C2864: either add a const modifier to your integer, or move the initialization outside the class (as in class Tester { static int number; }; int Tester::number = 5;). The latter seems more appropriate to your case.
Error C2146: you're missing a semicolon after the declaration of class Tester { ... }. It should be class Tester { ... };
The other errors are probably caused by the previous error. They should fix themselves automatically when it is fixed.
As a side note, I don't think you really want the static modifier on your member. It seems more appropriate for an instance field. You still can't initialize it in-place though (this isn't C#), you have to move the initialization to the constructor. For example:
class Tester {
int number;
static int staticNumber; // just to show you how to use a static field
public:
Tester() : number(5) {}
~Tester() {} // I suggest you remove the destructor unless you need it
int getNumber() { return number; }
void setNumber(int value) { number = value; }
static int getStaticNumber() { return staticNumber; }
static void setStaticNumber(int value) { staticNumber = value; }
};
// initialize static members *outside* the class
int Tester::staticNumber = 5;
According to this: http://publib.boulder.ibm.com/infocenter/lnxpcomp/v8v101/index.jsp?topic=/com.ibm.xlcpp8l.doc/language/ref/cplr038.htm
Tester testerObject;
int Tester::number = 5;
I'm not positive, but I think the rest of the errors come from that one problem.
Fix that, and see how far it gets you.
the answers already here deal with why your code doesn't compile and how to correct that. however i am intrigued by your comments about "extern". it is very easy to use when you know how. you declare in one header the extern'ed variable. and then you initialise it in one file. any other file can refer to the variable by including the header. e.g.
header.h:
// ensure the file is only included once
#ifndef _HEADER_H
#define _HEADER_H
extern int foo;
#endif
// end file header.h
header.cpp
#include "header.h"
int foo = 1;
// end file header.cpp
main.cpp
#include "header.h"
#include <stdio.h>
int main(int argc, char** argv)
{
printf("%d", foo);
return 0;
}
// end file main.cpp
Whilst using static class members for global variables helps fit the oo design scheme, its more elaborate than necessary. if you don't have to follow oo strictly, just use extern, its easier and its less code.