Hi Everyone,
I am trying to improve on how I write a program, I feel I may be picking up some bad habits from class and want to make sure I correct them. Here is my latest assignment, and suggestions on how to make it better? It builds and runs fine, I am looking at it from the point as if it would go to another programmer to utilize in a bigger program or even modify. Thanks for your feedback!!
using namespace std;
//------------------------------------------------------------------------------
// Define Employee Class
class Employee
{
// Declare Public Data Members
public:
// Constructors and Destructor
Employee();
Employee(string, string, char, int, double);
~Employee();
//Methods to Access Attributes
double calculatePay();
void displayEmployee();
My first suggestion is to use code tags when posting code in the forum to make your code readable.
Second the following is a very bad practice:
1 2 3
Header File
usingnamespace std;
You should never use a using statement inside a header file. Use the scope resolution operator:: to properly scope the namespace inside headers for example std::string test;
Next you include several unnecessary headers in your header file, and fail to include a required header file. You don't need either <iostream> or <iomanip> in employee.h but you do need the <string> include file.
Also, don't put the includes in the .cpp, just the header.
Actually I recommend that you include the proper include files in the location where these files are required. For example if you use the std::string class in a header either include the <string> in the header or if possible forward declare this class in your header. If you use the std::string class in a .cpp file include the <string> header in that file also. Never rely on some other file including an include file for you.
Generally, for school, using namespace std; is fine. If you're making something for yourself:
The OP was asking about best practices, it is never a good practice to use the using statement in a header file, however for small projects it is acceptable to use this statement in a .cpp file. However in my opinion you should get used to using the scope resolution operator:: everywhere.
"it is never a good practice to use the using statement in a header file"
That's an ambiguous statement since "using" has different meanings in different contexts. In some contexts, "using" is not bad practice regardless of location.
class Base
{
public:
virtualvoid method( int ) ;
virtualvoid method( constchar*) = 0;
};
class Derived : public Base
{
public:
using Base::method;
void method( constchar *) ;
};
class Base
{
public:
virtualvoid method( int ) ;
virtualvoid method( constchar*) = 0;
};
class Derived : public Base
{
public:
using Base::method;
void method( constchar *) ;
};
int main()
{
Derived test;
return 0;
}
main.cpp|18|undefined reference to `vtable for Derived'|
class Base
{
public:
virtualvoid method( int ) {}
virtualvoid method( constchar*)=0 ;
};
class Derived : public Base
{
public:
using Base::method;
void method( constchar *) {}
};
class Derived2 : public Base
{
public:
void method(constchar*) {}
};
int main()
{
Derived Test ;
Test.method(5) ;
Derived2 Test2 ;
Test2.method(5) ; // error
}
"I really don't see the point of your using statement."
...then you don't fully understand the usage of "using". When "using" is used inside a class, much like cire's example, it can be used to adjust the level-of-access of a derived member. Consider this example:
1 2 3 4 5 6 7 8 9
struct Base
{
int Member_; // Public
};
struct Child : Base
{
using Base::Member_; // "Member_" is still public
};
We can change this code to adjust the level-of-access of "Base::Member_"; like so:
1 2 3 4 5
struct Child : Base
{
private:
using Base::Member_; // "Member_" is now private
};
Please, read up on the effects and uses of "using" before labelling it as bad practice.
Thanks everyone for the comments, they are really appreciated. After reading them and listening to the lab tutorial on how they want this, I have made some changes. Still feel some fat can be trimmed, thoughts??
● You're not using initialiser-lists inside your constructors. Initialisation is far different that assignment. Note that initialisation is giving a variable or object a value during a declaration context.
● You're overloading the destructor of "Employee" when you don't need to.
● You're using magic constants which, when used by themselves, are not descriptive enough to deduce their usage. Prefer constants (for a single constant) or enumerations (for multiple constants) as these give a name to magic constant.
● Avoid excessive use of "std::ostream::endl( )". Prefer the use of the new-line character. Flush the stream before entering a function and before leaving a function.
● Avoid "using namespace ..." inside headers. This increases the possibility of identifier conflicts.
● (This one isn't bad practice, but it's recommended) It's best to declare variables or objects when you actually need them.
It's best to declare variables or objects when you actually need them.
... because objects call a function (the constructor) when they're instantiated.
If you get out of the function without ever using the object, you wasted a bit of time and memory.
Not sure what you mean about overloading the destructor. It is there even though it is not needed until next weeks assignment. Atleast is what I am told.
Can you give me an example on the magic constats, not sure I follow what you mean.
Have gone back and got rid of the endl, like below:
Working on the namepsace, the Professor wants to see it in there for now. Thnk you for the help and suggestions!
Thanks Cat, I am staring to understand more and more what you guys are saying, I have been making notess to keep with me so I can start doing things better as I write the code. Again I really appreciate your feedback!
Minor point: in C++, you don't need to put void in the parameter list of a function that doesn't take parameters. (In good old C, you do.)
Can you give me an example on the magic constats, not sure I follow what you mean.
He's most likely referring to hard-coded values.
1 2 3 4 5 6 7
while (n < 42) {} // bad style, 42 is a magic constant
constint defaultMaximum = 42;
// good style, we gave it a name,
// and we can change its value from a single place
while (n < defaultMaximum) {}
"Not sure what you mean about overloading the destructor. It is there even though it is not needed until next weeks assignment. Atleast is what I am told."
If you were told to overload it but not do anything with it then your hands are pretty much tied. But in your personal projects, overloading the destructor (defining a destructor inside a class overrides the destructor the compiler provides (the trivial destructor)) is only necessary if you want something to happen just before the object leaves its scope.
dudeman007 wrote:
"Can you give me an example on the magic constats, not sure I follow what you mean." (sic)
Magic constants are just real numbers such as 1, 10 and 500. In most cases, the use of magic constants do not provide enough information to justify their presence. For example, the following code contains magic constants. The constants used in the code will probably confuse you.
1 2 3 4 5 6 7 8 9 10 11
int SomeFunction( int Value_ )
{
switch( Value_ )
{
case 500:
// ...
case 502:
// ...
}
}
Anyone who reads the above code will, no doubt, will be confused by the magic constants; what do they mean? why are they there? To overcome this, we use named-constants. An example of a named-constant is as follows:
intconst NamedConstant( 10 );
As you can see, instead of the value 10, we have a name which we can refer to.