Ryuurei Posted February 5, 2010 Share Posted February 5, 2010 I've been working on some class testing to get back into C++, so I was once again trying to do things in a game-like way. I posted this on another thread but I don't think it was the right one. I created the following code: #include <iostream> using namespace std; //----------Class Player---------- class Player { protected: int Health, Damage; public: Player() { set(100, 10); } Player(int one, int two) { set(one, two); } int getHealth() { return Health; } int getDamage() { return Damage; } void set(int newHealth, int newDamage) { Health = newHealth; Damage = newDamage; } void Attack(Monster enemy); }; //----------Class Monster---------- class Monster { protected: int Health, Damage; public: Monster() { set(100, 10); } Monster(int one, int two) { set(one, two); } int getHealth() { return Health; } int getDamage() { return Damage; } void set(int newHealth, int newDamage) { Health = newHealth; Damage = newDamage; } }; //----------Test Function Prototypes---------- void TestPlayerFunctionality(); void TestMonsterFunctionality(); void TestAttackFunction(); //----------Main Function---------- int main() { TestPlayerFunctionality(); TestMonsterFunctionality(); //TestAttackFunction(); system("pause"); return 0; } //----------Player Class Functions---------- void Attack(Monster enemy) { enemy.set(enemy.getHealth() - Damage, enemy.getDamage()); cout << "After you attack, the enemy's health is " << enemy.getHealth() << "\n"; } //----------Test Functions---------- void TestPlayerFunctionality() { Player *you = new Player(120, 15); cout << "Your health is " << you->getHealth() << "\n"; cout << "Your damage is " << you->getDamage() << "\n"; delete you; } void TestMonsterFunctionality() { Monster *baddy = new Monster(20, 3); cout << "Monster's health is " << baddy->getHealth() << "\n"; cout << "Monster's damage is " << baddy->getDamage() << "\n"; delete baddy; } void TestAttackFunction() { Player *you = new Player(120, 20); Monster *baddy = new Monster(100, 15); you->Attack(baddy); delete you; delete baddy; } and just about everything works (although I commented out the TestAttackFunction() test to be worked on later. Upon compiling the code I have there, I receive the following errors: Line 16: "syntax error : identifier Monster" Line 51: " 'Damage' : undeclared identifier" Line 76: "Player::Attack function does not take 1 argument" I've revisited the Monster class, and it seems to be fine to me. The Damage variable IS obviously declared within either class (including the Player class which the function refers). The Player::Attack function does indeed take one argument, this makes no sense. I was using references, such as "void Attack(Monster const &enemy);" but doing so brought up even more, less understandable errors. Can anyone figure out what's going on here, because it is totally eluding me. Link to comment Share on other sites More sharing options...
0 Alton Posted February 5, 2010 Share Posted February 5, 2010 Hello To fix first error Line 16: "syntax error : identifier Monster" insert this lilne before class Player: class Monster; To fix other errors change this line void Attack(Monster enemy) to void Player::Attack(Monster enemy) when you declare function Attack - you declare global function, to declare class member function you must use Player::Attack Link to comment Share on other sites More sharing options...
0 Andre S. Veteran Posted February 5, 2010 Veteran Share Posted February 5, 2010 Your code makes sense, but C++ doesn't. You need to understand how (stupidly) it compiles. C++ compiles source files (.c and .cpp) going from top to bottom. Whenever it encounters a definition, it adds that to its symbol table (which is reset each time it compiles a new source file). Whenever it sees an identifier being used, it checks its symbol table to see whether that identifier has been seen before. If not, it emits an error. Simple as that. Now the burden is entirely on the programmer to feed the compiler the information it needs at the moment it needs it. This is counter-intuitive and tedious, fortunately there are some ways to alleviate the pain. To give you an example, the following compiles: class A {}; class B { A m_a; }; But the following doesn't: class B { A m_a; }; class A {}; Even though it's exactly the same code, in the second case, the compiler will see "A" before it knows what "A" is, so it will emit an error and stop there. So in your class "Player", you have this line: "void Attack(Monster enemy);". But Monster hasn't been defined yet, going from top to bottom, so the compiler will stop and complain "Monster" doesn't exist. The normal way around this issue, enabling you to code almost as if C++ made any sense, is to declare your classes each in their own header files, and implement them each in its own source file. You should be familiar with this pattern: MyClass.h: #pragma once class MyClass { int a; public: MyClass(); }; MyClass.cpp: #include "MyClass.h" MyClass::MyClass() { a = 0; } Yes it's a lot of fussing around, but C++ programmers don't do it for fun, they do it because it's the most painless way to deal with C++'s nonsense. Hope this helps. Ryuurei 1 Share Link to comment Share on other sites More sharing options...
0 Mike Posted February 6, 2010 Share Posted February 6, 2010 Your code makes sense, but C++ doesn't. You need to understand how (stupidly) it compiles. That is only your opinion. Fact is C++ compiles files like it would compile a function. You can't use a variable before it knows what it is just like any other language. Once you realise that functions need to be declared before they're used (just like variables) then coding in C/C++ is easy. d4v1d05 and brentaal 2 Share Link to comment Share on other sites More sharing options...
0 Andre S. Veteran Posted February 6, 2010 Veteran Share Posted February 6, 2010 Header files and declarations are just overhead that could be very well handled by the compiler, as modern languages like Java and C# prove. Why should I have to wonder whether to define something in the header or the cpp? Why should I have to manage inclusions and dependencies? Is there any logical reason why this will not compile? #include <cstdio> int main() { sayHello(); return 0; } void sayHello() { printf("Hello!"); } Sure, you get somewhat used to it, but it's still overhead and it still leads to mistakes and a longer development time, without any good reason. It also leads to much longer build times, and completely confuses newbies as Ryuurei demonstrates, and I've totally been there too. I lost hours tracking down circular includes, and I probably spent 30% of my time just waiting for recompiles at my first internship because the project was in C++. This is not the result of a careful design decision but of trying to build an object-oriented language on top of another ancient language, that was never designed for this. Ryuurei 1 Share Link to comment Share on other sites More sharing options...
0 Andre S. Veteran Posted February 6, 2010 Veteran Share Posted February 6, 2010 That is only your opinion. Fact is C++ compiles files like it would compile a function. You can't use a variable before it knows what it is just like any other language. Regarding that comment. Code within a function executes from top to bottom, so, sure, it's logical that an identifier needs to be defined before or at least at the point where it's first used. But functions within a file are not necessarily called from top to bottom. Classes are not used from "top to bottom", if such a concept can make any sense for classes :rofl: . There's no intuitive or logical reason for forward declarations besides doing the compiler's job.If it was just functions, like the original C, it'd be bearable... but add to that classes and templates (mainly templates) and everything falls apart pretty quickly. Ryuurei 1 Share Link to comment Share on other sites More sharing options...
0 hdood Posted February 6, 2010 Share Posted February 6, 2010 Header files and declarations are just overhead that could be very well handled by the compiler, as modern languages like Java and C# prove. Why should I have to wonder whether to define something in the header or the cpp? Why should I have to manage inclusions and dependencies? Is there any logical reason why this will not compile? Because C and C++ stem from the 1970s. Designing it the way you want simply was not possible, as the massive increase in resource use and build times would not be acceptable. This is the same reason Windows has many absurd and overly complex APIs and seemingly arbitrary restrictions. Much of Windows 7 was designed in the 1980s, with the restrictions of the hardware of the time. This is something we have to accept. Also, modern compilers support precompiling headers and can detect circular includes (as well as having flags that can mark a header as includable only once.) Link to comment Share on other sites More sharing options...
0 Mike Posted February 6, 2010 Share Posted February 6, 2010 Header files and declarations are just overhead that could be very well handled by the compiler, as modern languages like Java and C# prove. Why should I have to wonder whether to define something in the header or the cpp? Why should I have to manage inclusions and dependencies? It's a rather simple decision, put the functions in the C/CPP files, and the definitions in the header file. Is there any logical reason why this will not compile? <code snipped> You know why it won't compile. Sure, you get somewhat used to it, but it's still overhead and it still leads to mistakes and a longer development time, without any good reason. What sort of mistakes are you making? If you end up with different function definitions in the C/CPP file and the headers then you shouldn't be changing them - and if you do, you're not thinking when you do. Whenever you change some code you should know what else needs changing. completely confuses newbies as Ryuurei demonstrates, and I've totally been there too. I lost hours tracking down circular includes, and I probably spent 30% of my time just waiting for recompiles at my first internship because the project was in C++. You should be using something to stop circular inclusions the second you make the header file, anyone who has programmed in C/C++ for more than 5mins should know (and do) that. Of course C++ will take longer to compile - it has more to do, and you can't really compare it to Java/C# compilation as they work completely differently. d4v1d05 1 Share Link to comment Share on other sites More sharing options...
0 Andre S. Veteran Posted February 6, 2010 Veteran Share Posted February 6, 2010 Because C and C++ stem from the 1970s. Designing it the way you want simply was not possible, as the massive increase in resource use and build times would not be acceptable. This is the same reason Windows has many absurd and overly complex APIs and seemingly arbitrary restrictions. Much of Windows 7 was designed in the 1980s, with the restrictions of the hardware of the time. This is something we have to accept. Also, modern compilers support precompiling headers and can detect circular includes (as well as having flags that can mark a header as includable only once.) I know, I agree and I accept that C++ stems from the 1970s which explains many of its deficiencies. That doesn't make them good or logical features, just deficiencies. That's the only thing I'm arguing.Out of curiosity, what compilers are you talking about that detect circular includes? VS2008 gave me hell with those. It's a rather simple decision, put the functions in the C/CPP files, and the definitions in the header file.What if it's a template function? What if the function should be inline?You know why it won't compile.I know: it's not because of a logical reason, but because of a deficient compilation process.What sort of mistakes are you making? If you end up with different function definitions in the C/CPP file and the headers then you shouldn't be changing them - and if you do, you're not thinking when you do. Whenever you change some code you should know what else needs changing.It's more code, for starters: everytime you type code, you can type in mistakes. It's duplication, because the source file has or could very well have all the information needed. Code duplication leads to more mistakes as changes on one side won't automatically propagate to the other.Yes, there are some rules that one can abide by to avoid most problems related to header files, such as circular dependencies. But they are in no way intuitive and certainly not something you can grasp after a short exposure to C++ as you suggest. Everyone gets bitten by these and learns the hard way at some point. Look at the code Ryuurei posted. It's mostly logical, and there's no way he can resolve the compilation errors by tracking down logical errors. He's forced to open a C++ textbook (or ask here) to figure out what part of the clumsy syntax he's missed. This is the sign of bad language design. And yes, I happily compare C++ to Java and C#, because even though the latter compile to bytecode, this is not essentially why they compile much faster (besides they can be compiled to native code too, without taking nearly as long as C++). Machine code generation takes a tiny fraction of the time needed to compile C++: most of this is spent loading and parsing hundreds of header files, again and again for each source file, some of these header files containing very complex template code that will instantiate hundreds of classes that will later be optimized away. Did you know that "Hello World" using iostream causes the compiler to parse 700KB of source code? That's for the most simple, one-line-of-code C++ listing. Is that a sign of good language design? Link to comment Share on other sites More sharing options...
0 Ryuurei Posted February 6, 2010 Author Share Posted February 6, 2010 I think I've had to edit this post 5 times already :laugh: so I got the attack function "working" but things aren't going so well in the implementation. void Test() { player *you = new player(5000, 100); cout << "Your health is " << you->getHealth() << "\n"; cout << "\nYour damage is " << you->getDamage() << "\n"; monster *bad = new monster(300, 50); cout << "\nBad's health is " << bad->getHealth() << "\n"; cout << "\nBad's damage is " << bad->getDamage() << "\n"; you->Attack(bad); delete you; delete bad; } the Attack function is just: void player::Attack(monster enemy) { enemy.set(enemy.getHealth() - Damage, enemy.getDamage()); std::cout << "\nEnemy's health after attacking is " << enemy.getHealth() << "\n"; } For some reason, I get the compiler error saying that in Class.cpp (the main function source code), there is no matching function to call 'player::Attack(monster*&)' even though I'm directly sending "bad" as the argument. The compiler says that the candidates from player.h are "player::Attack(monster)" which is what I do believe I sent it. Link to comment Share on other sites More sharing options...
0 Andre S. Veteran Posted February 6, 2010 Veteran Share Posted February 6, 2010 player::Attack takes a "monster", but you pass it a "monster*". Just declare your test objects locally (much faster and less error-prone than calling new) player you(5000, 1000); you.getHealth() // blabla monster bad(300, 50); bad.getHealth() // blabla you.Attack(bad); // no need to delete Now, this won't do what you want because the monster will be passed by value, e.g. copied, so the function will modify its copy, leaving the original intact. You need to change the signature to pass by reference: void player::Attack(monster& enemy) Now no copy will occur and the original monster (the one declared in main) will be modified by the function. Link to comment Share on other sites More sharing options...
0 Ryuurei Posted February 6, 2010 Author Share Posted February 6, 2010 Ah, okay. Your solution there worked. If I did want to pass a pointer to an object, like I was trying to do before, what syntax would I use to do that? Also, if I were to write a "check if dead" function, could I use that function to delete a pointer to a monster, or can you only delete an object in the scope in which it is created? Link to comment Share on other sites More sharing options...
0 Andre S. Veteran Posted February 6, 2010 Veteran Share Posted February 6, 2010 If I did want to pass a pointer to an object, like I was trying to do before, what syntax would I use to do that?Keep your original syntax for the caller, just adapt the function signature: void player::Attack(monster* enemy) And yeah you can call delete on a pointer anytime, as long as it's pointing towards a live object that was created with new, it will work. Link to comment Share on other sites More sharing options...
0 Ryuurei Posted February 7, 2010 Author Share Posted February 7, 2010 Ah okay, I'll keep that in mind when I'm working with pointers. So I'm trying to build a silly little "hidden files" program for my friend. He wants something that will make a directory for him to hide files in, and have it password protected, so I'm trying my hand at a bit of windows-oriented programming. I got this put together: #include <iostream> #include <stdlib.h> #include <math.h> #include "windows.h" using namespace std; int main() { string Password = "PASSWORD"; string Input; system("mkdir Secret"); system("pause"); bool result; result = SetFileAttribute("C:\\Secret", FILE_ATTRIBUTE_HIDDEN); cout << "Enter a number: "; getline(cin, Input); if (Input == Password) { cout << "unlocked.\n"; result = SetFileAttribute("C:\\Secret", FILE_ATTRIBUTE_NORMAL); } else { double num = static_cast<double>( atoi(Input.c_str()) ); cout << "The square root is " << sqrt(num) << ".\n"; } system("pause"); return 0; } The compiler is saying that the SetFileAttributes was not declared in scope. Does anyone know how to properly use the function, and whether or not my code is at least logical? -Google wasn't really much help- This doesn't have to be some top-notch security program, I think he just wants it to hide files on his flash drive :laugh: Any help is appreciated. Link to comment Share on other sites More sharing options...
0 Andre S. Veteran Posted February 7, 2010 Veteran Share Posted February 7, 2010 Seems like you're just missing an 's' at the end of SetFileAttributes. ;) Link to comment Share on other sites More sharing options...
0 Ryuurei Posted February 7, 2010 Author Share Posted February 7, 2010 Ah okay, that solved the compile error. (Thats what I get for getting code from google searches haha). So I tried to use a function I got that gets the file directory and stores it in char CurrentPath. I tried passing that value (CurrentPath) along to the SetFileAttributes function but it doesn't seem to be actually hiding the file. Link to comment Share on other sites More sharing options...
0 Andre S. Veteran Posted February 7, 2010 Veteran Share Posted February 7, 2010 In C++ a string literal is a "const char*", so if you got a char* or const char* variable it's interchangeable. If you got an std::string you can get a const char* out of it with member function c_str(). Link to comment Share on other sites More sharing options...
0 Ryuurei Posted February 7, 2010 Author Share Posted February 7, 2010 Ah okay, it seems I got that figured out. The function does in fact take a char variable argument, so it runs. But it for some reason is having no affect on the file that I created. Link to comment Share on other sites More sharing options...
0 Andre S. Veteran Posted February 7, 2010 Veteran Share Posted February 7, 2010 Well it's supposed to set the file attribute "Hidden" to true, but of course that doesn't really hide the file in Windows, you can easily see it if you have changed your folder viewing options. Link to comment Share on other sites More sharing options...
0 Ryuurei Posted February 8, 2010 Author Share Posted February 8, 2010 Hm... I checked the status of the folder as it was being created, but there were ultimately no changes. I even enclosed the SetFileAttributes functions in while loops to test their effect. bool result = false; while (result == false) { result = SetFileAttributes(CurrentPath, FILE_ATTRIBUTE_HIDDEN); } and likewise with the function to set it back to normal (returning "result" to false, first). It seems however it just isn't having the desired effect. I think I'll just have to let this friend of mine know about the attrib command in the command line, haha. Well, Dr_Asik. I'd like to sincerely thank you for all the help you've given me these past few months. I've really learned a lot from you, and I truly do appreciate it. :yes: Link to comment Share on other sites More sharing options...
0 Andre S. Veteran Posted February 8, 2010 Veteran Share Posted February 8, 2010 I don't know what the problem is, having pretty much no experience with the Windows API, but that's the kind of thing I would do with a .bat or Python script instead of a C++ program. It's been a pleasure helping you out. You can always leave me a rep point somewhere. :p Ryuurei and ViZioN 2 Share Link to comment Share on other sites More sharing options...
Question
Ryuurei
I've been working on some class testing to get back into C++, so I was once again trying to do things in a game-like way.
I posted this on another thread but I don't think it was the right one.
I created the following code:
#include <iostream> using namespace std; //----------Class Player---------- class Player { protected: int Health, Damage; public: Player() { set(100, 10); } Player(int one, int two) { set(one, two); } int getHealth() { return Health; } int getDamage() { return Damage; } void set(int newHealth, int newDamage) { Health = newHealth; Damage = newDamage; } void Attack(Monster enemy); }; //----------Class Monster---------- class Monster { protected: int Health, Damage; public: Monster() { set(100, 10); } Monster(int one, int two) { set(one, two); } int getHealth() { return Health; } int getDamage() { return Damage; } void set(int newHealth, int newDamage) { Health = newHealth; Damage = newDamage; } }; //----------Test Function Prototypes---------- void TestPlayerFunctionality(); void TestMonsterFunctionality(); void TestAttackFunction(); //----------Main Function---------- int main() { TestPlayerFunctionality(); TestMonsterFunctionality(); //TestAttackFunction(); system("pause"); return 0; } //----------Player Class Functions---------- void Attack(Monster enemy) { enemy.set(enemy.getHealth() - Damage, enemy.getDamage()); cout << "After you attack, the enemy's health is " << enemy.getHealth() << "\n"; } //----------Test Functions---------- void TestPlayerFunctionality() { Player *you = new Player(120, 15); cout << "Your health is " << you->getHealth() << "\n"; cout << "Your damage is " << you->getDamage() << "\n"; delete you; } void TestMonsterFunctionality() { Monster *baddy = new Monster(20, 3); cout << "Monster's health is " << baddy->getHealth() << "\n"; cout << "Monster's damage is " << baddy->getDamage() << "\n"; delete baddy; } void TestAttackFunction() { Player *you = new Player(120, 20); Monster *baddy = new Monster(100, 15); you->Attack(baddy); delete you; delete baddy; }and just about everything works (although I commented out the TestAttackFunction() test to be worked on later.
Upon compiling the code I have there, I receive the following errors:
Line 16: "syntax error : identifier Monster"
Line 51: " 'Damage' : undeclared identifier"
Line 76: "Player::Attack function does not take 1 argument"
I've revisited the Monster class, and it seems to be fine to me.
The Damage variable IS obviously declared within either class (including the Player class which the function refers).
The Player::Attack function does indeed take one argument, this makes no sense.
I was using references, such as "void Attack(Monster const &enemy);" but doing so brought up even more, less understandable errors.
Can anyone figure out what's going on here, because it is totally eluding me.
Link to comment
Share on other sites
20 answers to this question
Recommended Posts