-1

I have a header class that refuses to cooperate, I've ironed a bunch of errors but cannot for the life of me get these two. Any ideas?

#pragma once
#include <iostream>
#include <string>
#include <conio.h>

using namespace std;
#ifndef EndageredSpecies
#define EndageredSpecies
using namespace std;
class EndageredSpecies
{
public:
    EndageredSpecies;
    EndageredSpecies(string newName, newLevel, newReason);
    void setName(string newName);
    void setLevel(string newLevel);
    void setReason(string newReason);
    string getName();
    string getLevel();
    string getReason();
    void print();
private:
    std::string name;
    std::string level;
    std::string reason;
};

void do_something()
{
    cout << "Doing something";
}
#endif

Errors are:

C2059 syntax error: ')' - line 13

C2238 sunexpected tokens preceding ';'- line 13

(Line 13 is 'EndageredSpecies(string newName, newLevel, newReason);')

  • 1
    You're missing the parenthesis after the EndangeredSpecies constructor, and your include guard has the same name as your class. – SeedyROM Feb 13 '19 at 02:16
  • 1
    Also you should only use `#pragma once`, and not the secondary guards you have. Remove all your other `#` macros. – SeedyROM Feb 13 '19 at 02:17
  • I added those parentheses when i first made the code, but all they do is throw an error that says "decleration does not declare anything". Doesnt effect the other 2 errors at all sadly. Im not sure what you mean when you say remove the other # macros. – Hank Logan Feb 13 '19 at 02:22
  • https://hastebin.com/uqavenevaf.cpp – SeedyROM Feb 13 '19 at 02:22
  • You need a corresponding .cpp file to be linked to your header, aka the implementation file. The error is most likely coming from you never implementing your default constructor. – SeedyROM Feb 13 '19 at 02:23

1 Answers1

1

What your code looks like to the compiler (note I have not processed the include statements as that, while more accurate, would make quite a mess):

#pragma once
#include <iostream>
#include <string>
#include <conio.h>

using namespace std;
using namespace std;
class 
{
public:
    ;
    (string newName, newLevel, newReason);
    void setName(string newName);
    void setLevel(string newLevel);
    void setReason(string newReason);
    string getName();
    string getLevel();
    string getReason();
    void print();
private:
    std::string name;
    std::string level;
    std::string reason;
};

void do_something()
{
    cout << "Doing something";
}

Why is this?

#define EndageredSpecies

tells the preprocessor to replace EndageredSpecies wherever it finds it with whatever is on the line after #define EndageredSpecies, absolutely nothing in this case, so

class EndageredSpecies

is now

class 

etc...

You have to be VERY careful with a #define macro. They are amazingly simple in execution. They have no brains whatsoever. If they see the token they've been told to replace, they replace it. Period. I once made the mistake of defining int strlen; to contain the length of a string.

Big Mistake.

It turned out the strlen function was implemented as a macro. int strlen; became int <whole function body here>;. I think I burned most of an afternoon figuring that out.

Do not fear the macro, but you have to use it very carefully.

What you really want is more like

#pragma once
#ifndef UNIQUE_AND_NEVER_REPEATED_IDENTIFIER
#define UNIQUE_AND_NEVER_REPEATED_IDENTIFIER
// note how this is above the includes. Don't want to re-include them

#include <iostream>
#include <string>
#include <conio.h>

// do not use using namespace std; in a header. It's a very nasty surprise 
// to other programmers.
class EndageredSpecies
{
public:
    EndageredSpecies(); // added brackets
    EndageredSpecies(std::string newName, // added std namespace 
                     std::string newLevel, 
                     std::string newReason);
    void setName(std::string newName);
    void setLevel(std::string newLevel);
    void setReason(std::string newReason);
    std::string getName();
    std::string getLevel();
    std::string getReason();
    void print();
private:
    std::string name;
    std::string level;
    std::string reason;
};

void do_something()
{
    std::cout << "Doing something";
}
#endif

An Aside:

#pragma once

and

#ifndef EndageredSpecies
#define EndageredSpecies
#endif

are two ways to make an include guard. You can use both, but typically you don't need to.

#pragma once

is not part of Standard C++, so you can't count on it being supported. Any pragma that a compiler does not support it is allowed to silently discard, leading to confusion, disaster, and possibly no useful error messages. That said, most compilers these days implement once. once likely has not been Standardized because it has severe failure cases in complicated build environments. Don't do anything sneaky and it works just fine.

#ifndef EndageredSpecies
#define EndageredSpecies
#endif

Works all the time everywhere. It's problems are the likes of what the asker has experienced.

Do not repeat a include guard identifier. Ever. For any reason.

Name include guards so that they will be next to impossible to repeat unless you are crazy. Sadly Norman Bates nailed it: We all go a little mad sometimes. To protect against temporary madness, make it as obvious as possible so when you are not mad later, you can see that the used identifier does not make sense where it is being used and change it.

You typically only want one or the other type of include guard, but there can be advantages to using both. If #pragma once is not supported or fails, you don't get the nasty surprise. If it is supported, there are often performance benefits from not having to look at the included file at all.

user4581301
  • 29,019
  • 5
  • 26
  • 45