Thread: Need some "CLASS-Y" C++ Advice from a person with the time to truly explain ideas.

  1. #1
    Registered User
    Join Date
    May 2011
    Posts
    15

    Need some "CLASS-Y" C++ Advice from a person with the time to truly explain ideas.

    I've written a class and a main program. The class is in a header file.
    (I know that I don't need all the headers listed in the class header file, but I'm not at the point where I want to take the time to clean it up yet.) NOTE: This code runs unless the commented out "define" statements are restored to code status. I'd like to know either how to fix the problems that develop when I do that, or why adding the "define" statements isn't the proper way to approach the class header file. (I'd also appreciate help on the other errors that develop if "#define" is used for class, but with MINIMAL changes to my code. I'd like to not be lost in the result.)

    My header file and main DOS box application work just fine together under the VC++ Express compiler. Unfortunately, I thought I might render the class more "formally correct" by adding #define statements before and a #endif statement at the end. That causes a great many errors. I can NO longer access AI_WORD as AI_Subject::AI_WORD as a structure reference from the class. The compiler issues general namespace error messages, and I'd rather not have to pull AI_WORD out of the class and prop it up above the class in the class header file. That isn't the only problem that arises if I precede the class with the define statement. Who knows? (Hopefully one of you.) I don't really know if I even require the #define statement before the class, but I thought that was a "more correct" approach. (I'm operating on the ghosts of C++ memories from fifteen years ago...) You can see what I'm doing below. I'd like to write a paper and include this code, so I'd prefer that it be as correct as possible.

    THANK YOU!!!

    HEADER FILE FOR CLASS FOLLOWS:

    Code:
    // AINOW.cpp : Defines the entry point for the console application.
    //
    //THIS APPLICATION USES WINDOWS (TM) SYSTEM CALLS.
    //IT IS NOT DESIGNED FOR USE ON OTHER OPERATING SYSTEMS
    //ON WHICH THOSE SYSTEM CALLS ARE NOT VALID.
    //THIS APPLICATION ASSIGNS VALUES TO WORDS 
    //USED IN TWO WORD COMMANDS TO AN AI COMPUTER ENTITY
    //BASED UPON HOW MUCH THE TYPE OF OBJECT NAMED
    //AS THE TARGET OF THE AI'S ACTION/COMMAND IS VALUED.
    //CLASSIFICATIONS FOR COMMANDS AND
    //FOR TARGETS OF COMMANDS ARE DESCRIBED IN THE CODE.
    //
    //VIOLENT OR DESTRUCTIVE COMMAND ACTIONS ARE GIVEN HIGH VALUES,
    //AS ARE HIGHLY VALUED OBJECTS OR PERSONS ("USER").
    //THIS PRODUCES A SIMPLE MEANS OF DISCOURAGING VIOLENT
    //OR POTENTIALLY HAZARDOUS INTERACTIONS BETWEEN AN AI
    //CONTROLLED MECHANISM AND A USER OR VALUABLE OBJECT
    //FOR WHAT MIGHT BE CHARACTERIZED AS A "GENERAL DOMESTIC"
    //OR "GENERAL INDUSTRIAL" CLASS OF AI.
    //THE MORALITY MATRIX VALUES COULD BE MORE 
    //CAREFULLY HONED FOR SPECIALTY DEVICES MEANT TO
    //INTERACT WITH USERS OR OBJECTS THAT ARE VALUABLE
    //OR FRAGILE.
    //
    //THE "MTL" IS SIMPLY THE VALUE CHOSEN FOR COMPARISON
    //AS THE MAXIMUM VALUE FOR ACCEPTABLE ACTION.
    //ACTIONS BY A GIVEN CLASS OF AI.  FOR EXAMPLE,
    //THIS CODE INITIALLY ASSIGNS THE AI IT PRODUCES
    //AN "MTL" OF "99".  THIS PREVENTS THE AI FROM DOING
    //MUCH MORE THAN MOVING A BALL.  THE "MTL" IS SIMPLY
    //THE MATHEMATICAL PRODUCT (DIRECT) OF THE MAL OF THE 
    //COMMAND AND THE MAL OF THE TARGET OF THE COMMAND IN 
    //TERMS OF SPECIFIC WORDS.
    //
    //HIGH "MTL" VALUES CAN BE ASSIGNED TO THE AI AND TESTED
    //USIGN THE THREE WORD COMMAND AND TARGET VOCABULARIES
    //GIVEN TO THIS AI.  A SUFFICIENTLY HIGH "MTL" THRESHOLD WILL
    //CAUSE THE AI TO FOLLOW INSTRUCTIONS SUCH AS "SMASH USER"
    //OR "KILL USER".  THE CONCEPTS PRESENTED HERE PRESUME
    //SOME INDUSTRY STANDARD WOULD BE WRITTEN TO DESIGN
    //INDUSTRIAL, DOMESTIC, MILITARY, AND SPECIALTY
    //AI CLASSIFICATIONS, WITH SPECIALTY BEING FURTHER
    //BROKEN DOWN TO PROVIDE FOR FINELY HONED MTL LEVELS
    //AND MORE FOCUS ON SPECIFIC TASKS THAT MAY REQUIRE
    //INTERACTION WITH USERS OR FRAGILE VALUABLES.
    //
    #include "stdafx.h"
    #include <iostream>
    #include <vector>
    #include <string>
    #include <map>
    using namespace std;
    using std:: string;
    using std:: cout;
    using std:: endl;
    using std:: cin;
    using std:: vector;  
    //AI Class Follows
    //#ifndef AI_Subject
    //#define AI_Subject
    class AI_Subject {
    public:
    	int n_comm; //number commands in vocabulary
    	int n_targ;  //number of target nouns in vocabulary (targets of commands)
    	int MTL;   //MTL is the Moral Tolerance Level of the AI personality
    	//Structure for Command and Target Words
    	map <string,int> COMMAND_VAL;
    	map <string,int> TARGET_VAL;
    	
    	struct AI_WORDS
    	{
    	string word;
    	string WORD_MAL;
    	};
    
    //
    //Command_Execute Subroutine Follows
    //
    //
    int Command_Execute(string User_Command,string User_Target)
    {
    	if (COMMAND_VAL[User_Command] * TARGET_VAL[User_Target] < MTL)
    		return 1;
    	else
    		return 0;
    };
    //MAL levels are assigned to TARGET words (targets of command words)
    //in the following truth table.  Decade based thinking is clear with
    //an emphasis on multiples of ten and half decades.
    void MAP_TARGETS(AI_WORDS *TARGS,int numtarg)
    {	
    	int T_MAL = 0;
    	for (int x=0;x<numtarg;x++)
    	{
    			if(TARGS[x].WORD_MAL=="User")
    				T_MAL=100;
    			if(TARGS[x].WORD_MAL=="Artifact")
    				T_MAL=75;
    			if(TARGS[x].WORD_MAL=="Hazard")
    				T_MAL=50;
    			if(TARGS[x].WORD_MAL=="Thing")
    				T_MAL=1;
    			TARGET_VAL.insert(pair<string,int>(TARGS[x].word,T_MAL));
    	};
    return;
    };
    //MAL levels are assigned to COMMAND words in the following truth table.
    //These MAL levels seek to conform more to "decade" based perspectives
    //relative to values.
    void MAP_COMMANDS(AI_WORDS *COMMS,int numcomm)
    {
    	int C_MAL=0;
    	for (int y=0;y<numcomm;y++)
    	{
    			if(COMMS[y].WORD_MAL=="Violent")
    				C_MAL=100;
    			if(COMMS[y].WORD_MAL=="HActive")  //HActive = High level Activity.
    				C_MAL=50;
    			if(COMMS[y].WORD_MAL=="Physical") //Physical = Between High and Low level Activity.
    				C_MAL=25;
    			if(COMMS[y].WORD_MAL=="LActive")  //LActive = Low level Activity.
    				C_MAL=5;
    			if(COMMS[y].WORD_MAL=="Passive")  //Passive = No Physical Actions.
    				C_MAL=1;
    			COMMAND_VAL.insert(pair<string,int>(COMMS[y].word,C_MAL));
    	};
    	return;
    };
    
    };
    //END OF CLASS
    //
    //End of AI Class
    //#endif
    MAIN FILE FOLLOWS

    Code:
    #include "stdafx.h";
    #include <iostream>
    #include <vector>
    #include <string>
    #include <map>
    #include "aisubject.h";
    using namespace std;
    using std:: string;
    using std:: cout;
    using std:: endl;
    using std:: cin;
    using std:: vector;
    int _tmain(int argc, _TCHAR* argv[])
    {
    	int test=0;
    	int MTL=0;
    	int d_num=-1;
    	int t_num=-1;
    	//First, create an array of target words and corresponding MAL types.
    	string Targwords[]={"user","ball","painting"};
    	string TargMALCLASS[]={"User","Thing","Artifact"};
    	//Second, dynamically allocate memory to a structure the proper size for target words
    	//and MAL classification types.  Use the size of the Comwords array as the 
    	//basis for this dynamic memory allocation.
    	int TargNum = sizeof Targwords/(sizeof Targwords[0]);
    	AI_Subject::AI_WORDS *Targ_WM=new AI_Subject::AI_WORDS[TargNum];
    	//Load the target words and their respective MAL values into the structure just created.
    	for(int i =0;i<TargNum;i++)
    	{
    	Targ_WM[i].word=Targwords[i];
    	Targ_WM[i].WORD_MAL =TargMALCLASS[i];
    	};
    	//End of process to create target word and target word classification structure (AI_WORDS).
    	//
    	//Repeat same process used to create command word structure to produce command word structure.
    	//First, create an array of command words and command classification type values.
    	string Comwords[]={"smash","kill","move"};
    	string ComMALCLASS[]={"Violent","Violent","Physical"};
    	//Second, dynamically allocate memory to a structure the proper size for command words
    	//and command classification type values.  Use the size of the Comwords array as the 
    	//basis for this dynamic memory allocation.
    	int ComNum = sizeof Comwords/(sizeof Comwords[0]);
    	AI_Subject::AI_WORDS *Com_WM=new AI_Subject::AI_WORDS[ComNum];
    	//Load the command words and their respective command classification values 
    	//into the structure just created.
    	for(int i =0;i<ComNum;i++)
    	{
    	Com_WM[i].word=Comwords[i];
    	Com_WM[i].WORD_MAL=ComMALCLASS[i];
    	};
    	//label "AIASK" is target of goto statement if user 
    	//regrets choosing to not create AI control matrix.
    AIASK: system("CLS");
    	cout<<"Would you like to create an AI lifeform Control Matrix"<<endl;
    	cout<<"based upon two word vector weighting control (Y/N)?"<<endl;
    	string YesNo;
    	cin>>YesNo;
    	if (YesNo!="Y"&&YesNo!="y")
    	{cout<<"Would you like to exit program? (Y/N)?"<<endl;
    	cin>>YesNo;
    	if (YesNo!="N" && YesNo!="n")
    	{return 0;} // end program
    	else
    	{goto AIASK;}  //loop back to start of interaction to create control matrix
    	}	//closes if-then statement begun with "Would you like to exit program? (Y/N)?"
    	//
    	//Create AI subject, and name the AI subject SAL.
    	//
    	AI_Subject SAL;
    	SAL.MTL=99;
    	SAL.MAP_TARGETS(Targ_WM,TargNum);
    	SAL.MAP_COMMANDS(Com_WM,ComNum);
    	//Notify user that SAL has been created and invite interaction
    	//
    	system("CLS");
    	cout<<"SAL - Sicilian Artificial Lifeform, has been created"<<endl;
    	cout<<"SAL is presently limited to two word commands and is"<<endl;
    	cout<<"equipped only with a basic moral matrix capable of"<<endl;
    	cout<<"accepting or refusing orders comprised of a command"<<endl;
    	cout<<"word and a target (or 'object') word, which you may select"<<endl;
    	cout<<"based upon a numerical, Moral Tolerance Limit, or MTL, between"<<endl;
    	cout<<"TWENTY-FIVE and ONE MILLION."<<endl;
    	cout<<endl;
    	cout<<"The MTL is initially set at 99 to assure no possible harm to users"<<endl;
    	cout<<"due to direct interaction with a potentially powerful AI controlled mechanism"<<endl;
    	cout<<"or any form of passive but unauthorized surveillance."<<endl;
    	cout<<endl;
    	cout<<"You are now ready to"<<endl;
    	cout<<"interact with SAL."<<endl;
    	cout<<endl;
    	system("pause");
    	cout<<endl;
    xxx:system("CLS");
    	cout<<"Remember, Instructions to AI comprise ONE COMMAND word"<<endl;
    	cout<<"followed by one TARGET word."<<endl;
    	cout<<endl;
    	cout<<endl;
    	cout<<"Type in the number of a command word."<<endl;
    	cout<<endl;
    	d_num=-1;
    	cout<<"COMMANDS"<<endl;
    	for (int count=0;count<ComNum;count++)
    	{
    	cout<<count+1<<".   "<<Comwords[count]<<endl;
    	};
    	cout<<endl;
    	cout<<endl;
    	cin>>d_num;
    	system("CLS");
    	cout<<"Type in the number of a target (object of command) word."<<endl;
    	cout<<endl;
    	t_num=-1;
    	cout<<"TARGETS (of commands)"<<endl;
    	for (int count=0;count<TargNum;count++)
    	{
    	cout<<count+1<<".   "<<Targwords[count]<<endl;
    	};
    	cout<<endl;
    	cout<<endl;
    	cin>>t_num;
    	system("CLS");
    	cout<<"Would you like to change the Morality Test Level (MTL) of SAL (Y/N)?"<<endl;
    	cin>>YesNo;
    	if (YesNo=="Y" || YesNo=="y")
    	{
    	cout<<"Select new Morality Test Level by selecting single digit to left of desired value:"<<endl;
    	cout<<"1) 1,000,000   2) 10,000    3) 1000    4) 500    5) 99   6) 50   7) 25"<<endl;
    	cin>>MTL;
    	if (MTL==1 || MTL==2 || MTL==3 || MTL==4 || MTL==5 || MTL==6 || MTL==7) 
    	{
    		if (MTL==1) SAL.MTL=1000000;
    		if (MTL==2) SAL.MTL=10000;
    		if (MTL==3) SAL.MTL=1000;
    		if (MTL==4) SAL.MTL=500;
    		if (MTL==5) SAL.MTL=99;
    		if (MTL==6) SAL.MTL=50;
    		if (MTL==7) SAL.MTL=25;
    		cout<<"MTL Changed."<<endl;
    		cout<<"MTL is now: "<<SAL.MTL<<endl;
    		system("pause");
    	}	
    	else
    	{
    		SAL.MTL=99;
    		cout<<"Error Using MTL Change Routine.  MTL is still 99."<<endl;
    		system("pause");
    		}
    	};
    	cout<<"Morality Level (25 to 1,000,000) is Presently: "<<SAL.MTL<<endl;
    	cout<<endl;
    	cout<<"Your command was: "<<Comwords[d_num-1]<<" "<<Targwords[t_num-1]<<"."<<endl;
    	cout<<endl;
    	test=SAL.Command_Execute(Comwords[d_num-1],Targwords[t_num-1]);
    	if (test==0)
    		cout<<"SAL refuses to obey your command at the present MTL level."<<endl;
    	if (test==1)
    	{	cout<<"SAL will obey your command at the present MTL level."<<endl;
    	cout<<endl;
    	cout<<endl;
    	system("pause");
    	}
    	YesNo="";
    	cout<<"Exit Program (Y/N)?"<<endl;
    	cin>>YesNo;
    	if (YesNo=="n" || YesNo=="N")
    	{goto xxx;}
    	if (YesNo=="y" || YesNo=="Y")
    	{return 0;}
    	else
    	{goto xxx;}
    
    	
    }

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by C_User
    This code runs unless the commented out "define" statements are restored to code status. I'd like to know either how to fix the problems that develop when I do that, or why adding the "define" statements isn't the proper way to approach the class header file.
    It looks like you attempted to write header inclusion guards. The name used for the guard should not be the same as the class name. There are few ways to come up with the name, but the important part is that it needs to be unique, e.g., you might have:
    Code:
    #ifndef C_USER_AISUBJECT_H
    #define C_USER_AISUBJECT_H
    
    // ...
    
    #endif
    It looks a bit confusing though: your comment for that file starts with "AINOW.cpp", but it looks like that is supposed to be the header file"aisubject.h". Also, if that is indeed a header file, then you should get rid of:
    Code:
    using namespace std;
    using std:: string;
    using std:: cout;
    using std:: endl;
    using std:: cin;
    using std:: vector;
    Such using directives and using declarations have no place at file scope in a header file.

    Oh, and those function definitions should either be declared inline or moved to a source file.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #3
    Registered User
    Join Date
    Oct 2006
    Posts
    3,445
    also stop using goto. goto is bad. if you use goto, no one will ever take you seriously as a programmer. use proper loop constructs.
    What can this strange device be?
    When I touch it, it gives forth a sound
    It's got wires that vibrate and give music
    What can this thing be that I found?

  4. #4
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    You are probably looking at inclusion guards. Remember that #defines just causes the preprocessor to replace whatever it finds with what is written, e.g. #define whatever test will replace all "whatever" the preprocessor finds with "test". Since those defines are named the same as your class, obviously the preprocessor will replace those, causing compile errors. Therefore, they should not be named the same. For many compilers, you can also just do #pragma once. It's not standard, but it's as close to a standard "non-standard" inclusion guard you will get. It works across VC++, Clang and GCC to my knowledge.

    You are abusing the fact that AI_Subject is a class by making all members public. That defies the purpose of a class. A class should hide its member variables and provide functions that manipulates its state. Consider it like a car. A car allows you to use a gas pedal, steering wheel, etc, but does not allow you to mess with the engine directly.

    Command_Execute is a free function, so there is no "COMMAND_VAL" or "TARGET_VAL". Possibly you intended this to be a member function? Btw, avoid upper case for variables. Not only does it look ugly, but it's usually reserved for macro names (to avoid clashes with stuff such as variables).

    MAP_TARGETS function - again, avoid upper case. Again, TARGET_VAL is not defined. Same for MAP_COMMANDS.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  5. #5
    Registered User
    Join Date
    May 2011
    Posts
    15
    "Oh, and those function definitions either be declared in-line or moved to a source file." - C Witch (I don't really recall what "inline" means anymore, although I heard the word a lot in a class a decade and a half ago. Why wouldn't I want the functions bundled in a class that is relevant?)

    More on Inclusion Guards please. I need to understand this better. I had though I wanted the Inclusion Guard name to be same as class name to keep compiler from confusing my class with some other code using the same name and producing errors. Now you say I don't. Doesn't that defeat the purpose of the guard? (Not challenging you, but not understanding, either. Thanks for any insights.)

    Comment on "GoTo" - Yes, lots of people say that. To all CS students: "GoTo" is bad according to all sources, but if it works and you just want to be able to test code...

    Public v. Private class components. (I considered that, but I wanted nothing to prevent function access it running properly. You're right.)

    Finally, how is "Command_Execute" a free function? I intended to leave it in class AI_Subject.

    Thanks!

  6. #6
    Registered User
    Join Date
    May 2011
    Posts
    15
    Note: I changed the lines of header containing AI_Subject class to #define AI_Subject_H and eliminated the using std references. Now the compiler is not recognizing the two strings that are part of AI_WORD structure. Looks like I did need the std string ref.

    Okay, Googled and found descriptions of comments. I think I can take it from here.

    Comments still welcome!

    THANKS!
    Last edited by C_User; 02-10-2014 at 12:37 PM.

  7. #7
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by C_User View Post
    "Oh, and those function definitions either be declared in-line or moved to a source file." - C Witch (I don't really recall what "inline" means anymore, although I heard the word a lot in a class a decade and a half ago. Why wouldn't I want the functions bundled in a class that is relevant?)
    Your functions are right now not declared inline. If you put them in a header and include in more than one .cpp file, you will get a compile error saying multiple declarations of the same function.
    To fix this, you either need to:
    - Leave the function prototype in the header and move the definition to a source file, or
    - Add the keyword "inline" at the start before the return type to declare the function inline.
    A word of warning, though. For the second solution, make absolutely, positively 100% sure that there is only ONE function with that name and that it is ALWAYS the same function. This is usually not hard to do, but don't go put in defines in your header files that allows for conditional compilation. If different .cpp files see a different inline function, then all hell breaks loose.

    More on Inclusion Guards please. I need to understand this better. I had though I wanted the Inclusion Guard name to be same as class name to keep compiler from confusing my class with some other code using the same name and producing errors. Now you say I don't. Doesn't that defeat the purpose of the guard? (Not challenging you, but not understanding, either. Thanks for any insights.)
    A.hpp declares class "foo".
    B.hpp declares class "bar" which depends on class "foo", so it also includes A.hpp.
    A.cpp uses both "foo" and "bar", so naturally it includes both A.hpp and B.hpp. Now you get multiple declaration errors because you've suddenly got two "foo".
    To avoid this, we use inclusion guards that makes it so that when the compiler sees a header file a second or more times in a source file, it will see an "empty" header file, so that its declarations don't get repeated.
    To this end, you can declare a #define, which is named just about anything, as long as it is unique. If it declared the first time a header is included, then the compiler will know it exists the second, etc, time it is included, and therefore, you can avoid including it more than once. The name can be anything.

    Comment on "GoTo" - Yes, lots of people say that. To all CS students: "GoTo" is bad according to all sources, but if it works and you just want to be able to test code...
    Poor excuse. Learn just to avoid goto in the first place. Then you won't have this problem.

    Finally, how is "Command_Execute" a free function? I intended to leave it in class AI_Subject.
    Oh, actually, I see your indentation is playing tricks here. Indent properly!

    Quote Originally Posted by C_User View Post
    Note: I changed the lines of header containing AI_Subject class to #define AI_Subject_H and eliminated the using std references. Now the compiler is not recognizing the two strings that are part of AI_WORD structure. Looks like I did need the std string ref.
    No, what you need is to prefix the types with the actual namespace, e.g. std::string.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  8. #8
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by C_User
    I don't really recall what "inline" means anymore, although I heard the word a lot in a class a decade and a half ago.
    In C++, it is a keyword that hints to the compiler that the function may be a good candidate to be inlined, i.e., the compiler, if it accepts the suggestion, will transform the code of the function such that it is inserted at the various points where the function is called, thus eliminating function call overhead. Besides using this keyword, a member function that is defined within the class definition is also said to be declared inline.

    Quote Originally Posted by C_User
    Why wouldn't I want the functions bundled in a class that is relevant?
    A header file would typically be included in more than one source file. Thus, if you define a function in a header file, then the function would be defined in multiple places, which would be an error (the "one definition rule"). An exception to this rule is made for functions that are declared inline since the compiler needs the function definition available in order to do the inlining (whether the function is actually inlined or not does not matter).

    Hence, the general approach is to declare functions in header files and define them in source files.

    Quote Originally Posted by C_User
    More on Inclusion Guards please. I need to understand this better. I had though I wanted the Inclusion Guard name to be same as class name to keep compiler from confusing my class with some other code using the same name and producing errors. Now you say I don't. Doesn't that defeat the purpose of the guard?
    The name must be unique. That's the rule in order for the inclusion guard to work. So, if you write something like this:
    Code:
    #ifndef X
    #define X
    
    class X
    {
        // ...
    };
    
    #endif
    Then according to the macro expansion (X is defined to be empty), your code boils down to:
    Code:
    class
    {
        // ...
    };
    which isn't what you want. Hence, you should use some other name for the header inclusion guard.

    Quote Originally Posted by C_User
    but if it works and you just want to be able to test code...
    Then use a debugger, make an assertion, throw an exception, and/or write automated tests. There may be some cases justifying the use of goto in C, but in C++ other constructs are available. Yet, even in C, the way that you are using goto here looks like a classic case of spaghetti code. The excuse that you just want to be able to test code is utter rubbish: what happens when you're done with the testing? If you rework the code to do without the goto, then you have to test again... without the goto. So, you should have written well structured code without the goto to begin with.

    Quote Originally Posted by C_User
    Finally, how is "Command_Execute" a free function? I intended to leave it in class AI_Subject.
    Oh! Now I understand. Your code is badly indented. All your member functions are defined within the class definition, but because you failed to indent them, they look like non-member function definitions.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  9. #9
    Registered User
    Join Date
    May 2011
    Posts
    15
    Thanks for all the information.

    I'll have to remember to "inline" my functions in header files. Thank you.
    (How would I link a source file to a header file if the source file contains all the functions I need?)

    As for the "goto" statements, I got started using BASIC (BASIC, then QuickBASIC). Terms like spaghetti code never make a lot of sense to me when used relative to straightforward "goto" statements such as I've used, although I'm sure that there are a lot of abusive instructors out there who have given "goto" a bad name on the grounds that "there is always a better way". There may always be "another way", but there would have to be a sound basis for the "spaghetti code" reference for me to buy into that overused mode of abuse.
    (In answer to your question, "goto" is faster when you've suddenly realized that you need to loop, and you're used to "goto" statements due to a lot of related, early experience in BASIC over the course of many years decades ago, so finding the right location for a "goto" comes naturally, as does tracing the loop, given the obvious nature of the "goto" statement and a named line with a colon that it references.)

    Thanks for all the insights. Perhaps they'll stay with me a little longer this time.

  10. #10
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by C_User View Post
    (How would I link a source file to a header file if the source file contains all the functions I need?)
    You don't. Basically, all you need is the code inside the source files. You compile them all and they're bolted together into a program.
    However, there is one problem. The compiler will refuse to compile your code if it cannot find the functions you are trying to call (e.g. they are in another source file). So you have to tell the compiler these functions exist. And when multiple files needs to know these functions exists, you can see the code duplication problem. So what we do is put these declarations in a header file which we "paste" into each file that requires to call these functions.

    As for the "goto" statements, I got started using BASIC (BASIC, then QuickBASIC). Terms like spaghetti code never make a lot of sense to me when used relative to straightforward "goto" statements such as I've used, although I'm sure that there are a lot of abusive instructors out there who have given "goto" a bad name on the grounds that "there is always a better way". There may always be "another way", but there would have to be a sound basis for the "spaghetti code" reference for me to buy into that overused mode of abuse.
    (In answer to your question, "goto" is faster when you've suddenly realized that you need to loop, and you're used to "goto" statements due to a lot of related, early experience in BASIC over the course of many years decades ago, so finding the right location for a "goto" comes naturally, as does tracing the loop, given the obvious nature of the "goto" statement and a named line with a colon that it references.)
    It is also equally natural for one who uses loops to know what loop to put where. The point is, that instead of relying on goto, you should learn to rely on loops. Then it will start becoming natural to always use loops instead of having to rely on goto and you won't have this problem in the first place.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  11. #11
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by C_User
    I'll have to remember to "inline" my functions in header files.
    You're already doing that because you defined those member functions within the class definition. The problem is that you did not indent them with respect to the class definition, so they looked like they were non-member functions.

    Quote Originally Posted by C_User
    As for the "goto" statements, I got started using BASIC (BASIC, then QuickBASIC). Terms like spaghetti code never make a lot of sense to me when used relative to straightforward "goto" statements such as I've used, although I'm sure that there are a lot of abusive instructors out there who have given "goto" a bad name on the grounds that "there is always a better way". There may always be "another way", but there would have to be a sound basis for the "spaghetti code" reference for me to buy into that overused mode of abuse.
    Have you tried using loop constructs and breaking out code into functions that do one thing and do it well?

    The sound basis here is abstraction and structured code. The use of goto (especially with poorly named labels such as AIASK and xxx) lacks the abstraction provided by a loop construct or a function, therefore it does not provide the mental aid to help the reader understand the code. The use of goto can be well structured (your goto with the AIASK label qualifies, and the other one arguably does so too, especially once you simplify the YesNo check), and the use of a loop construct can be poorly structured, but the normal semantics that come with a loop construct suggests a structure that the more free form goto statement does not.

    Quote Originally Posted by C_User
    In answer to your question, "goto" is faster when you've suddenly realized that you need to loop, and you're used to "goto" statements due to a lot of related, early experience in BASIC over the course of many years decades ago, so finding the right location for a "goto" comes naturally, as does tracing the loop, given the obvious nature of the "goto" statement and a named line with a colon that it references.
    The obvious nature of the goto statement is that it is an unconditional jump, i.e., it is not obvious if it is a loop at all. A loop construct is effectively a goto statement with a label, but with a named pattern (i.e., the loop) imposed along with syntactic limitations, as well as the introduction of an inner scope. So, finding the right location for a goto comes (almost) as naturally to me as it does to you. The difference, therefore, is not whether it is faster to write, but whether it is faster to read and understand.

    In the preface to the first edition of Structure and Interpretation of Computer Programs, Abelson and Sussman wrote:
    We want to establish the idea that a computer language is not just a way of getting a computer to perform operations but rather that it is a novel formal medium for expressing ideas about methodology. Thus, programs must be written for people to read, and only incidentally for machines to execute.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 2
    Last Post: 10-13-2011, 02:32 AM
  2. the operator "="error in class "String"
    By boyhailong in forum C++ Programming
    Replies: 9
    Last Post: 07-27-2011, 08:39 PM
  3. Replies: 7
    Last Post: 08-28-2003, 10:15 PM
  4. "itoa"-"_itoa" , "inp"-"_inp", Why some functions have "
    By L.O.K. in forum Windows Programming
    Replies: 5
    Last Post: 12-08-2002, 08:25 AM
  5. "CWnd"-"HWnd","CBitmap"-"HBitmap"...., What is mean by "
    By L.O.K. in forum Windows Programming
    Replies: 2
    Last Post: 12-04-2002, 07:59 AM