Link to home
Start Free TrialLog in
Avatar of jandhb
jandhb

asked on

strings/classes

First, I'm new at using classes and have what I believe to be a farely simple question here. I appreciate the help in advance.
-----------------------
I have a console application that is using a class called family. Here it is so far...
class family
{
private:
      float firstName;
public:
      float getName(float);
};
#endif
---------------------
I also have .h file that has a function in it called getName. Here it is so far...
#include <iostream.h>
#include "family.h"

float family::getName (float d)
{
      firstName = d;
      return firstName;
}
-----------------------
I have another .cpp file....
#include <iostream.h>
#include "family.h"

void main (void)
{
      family member;
      float dad;
      cout<<"Who is the dad?";
      cin >> dad;
      cout<<"His child is then " <<member.getName(dad);
}

where I would like to ask for the father's name and return the children of that family based upon the input. I know I will have to add some to the function, but can you help with that if you have a minute. And also, right now when I enter say, "M" for the dad it returns some random number like -1.07374e+008.

Can you help me with the function and what is needed to be able to retun char data instead of numeric?

Again, thank you.
jandhb

Avatar of jandhb
jandhb

ASKER

I changed the function in family.cpp to this...
#include <iostream.h>
#include "family.h"
#include <string.h>
using namespace std;

void family::getName (string &dad)
{
      char members[1][15] = {"Heather"};
      char lookUp[15], *strPtr = NULL;
      int index;

      for (index=0; index <1; index++)
      {
            strPtr = strstr(members[index],lookUp);
            if(strPtr !=NULL)
                  break;
      }
      if (strPtr == NULL)
            cout << "No mathches";
      else
            cout <<members[index]<<endl;
}
-----------------
In family_prog.pp I have...
#include <iostream.h>
#include "family.h"
#include <string>
using namespace std;


void main (void)
{
      family member;
      string dad;
      cout<<"Who is the dad?";
      cin >> dad;
      cout<<"His child is then " <<member.getName(dad);
}
-----------------------
And in the family.h I have...
#ifndef family_h
#define family_h
#include <string>
using namespace std;

//family class declaration
class family
{
private:
      string &father;
public:
      void getName(string&);
};
#endif
--------------------
Now I am getting an error that says...
No appropriate default constructor available. What does that mean? I am using VC++6.0.
Also, am I using the string.h right when trying to read in and pass this as a parameter to the function?
family::father is a reference.  References have to be initialized when they are created.  The compiler is telling you that it can't create a family object because there is nothing that initializes that reference.  You could initialize the reference in a constructor or make family::father a string rather than a reference to a string.

The string-handling code in main looks OK.  The code for the family class needs work.

--efn
Also, don't mix <iostream.h> with <string>. Use <iostream>.
Your class is still strange even if you don't use type float (that's a floating point number with binary storage)  for names:

>> string dad

If you use STL string - what is good - don't mix it up with char[] or char* if it isn't necessary. So your class should look like

#ifndef family_h
#define family_h
#include <string>
#include <vector>
using namespace std;

//family class declaration
class Family
{
private:
     string familyName;
     string father;
     string mother;
     vector<string> children;
public:
     Family();
     Family(const string& familyName, const string& dad , const string& mom);
     void setFamilyname(const string& familyName);
     void setFather(const string& dad);
     void setMother(const string& mom);
     void addChild(const string& child);
     string getFamilyName();
     string getFather();
     string getMother();
     string getChild(int i);
     vector<string>& getChildren();
};
#endif

You see, the only reference returned is vector<string>& as it isn't common to return an array by value (means as a copy).
Member data like father, mother, ... shouldn't declared as reference or you have to provide a storage for them at construction time:

class Family
{
private:
     string& father;
public:
     Family(const string& dad) :  father(*new string(dad)) {}
    ~Family()   {  delete &father; }
};

That compiles but might be a little bit too advanced for a beginner ;-)

>> void family::getName (string &dad)

Change it to

  string family::getFather()

as a get function returning only one value shouldn't return the value by argument. Then you can use it like

  Family myFamily("Smith", "Bob", "Mary");
  string dad = myFamily.getFather();

>>      char members[1][15] = {"Heather"};

As mentioned before, use string class instead of char arrays and if you need an array take std::list or std::vector. If you choose a fix size,  a woman's name like "Marie-Antoinette" won't fit to the buffer.

  vector<string> children;
  children.push_back("Heather");

>>     char lookUp[15], *strPtr = NULL;

First, use string instead char ...  Then lookup isn't initialized and later used. You should always initialize all variables; however you don't have to initialize a string type as it is initialized by the constructor (as an empty string).

>>      for (index=0; index <1; index++)

With string and vector you would have:

    for (index=0; index < children.size(); index++)

>>          strPtr = strstr(members[index],lookUp);
>>          if(strPtr !=NULL)
>>               break;

strstr() searches a substring in a string. You would find "John" in "Johnathan" for example. You should compare both values:
     
       vector<string> members;
       members.push_back("John");
       members.push_back("Heather");
       for (int index=0; index < members.size(); index++)
           if (members[index] == dad)
               break;

Then lookup wasn't initialized. I think you wanted to lookup for 'dad' ??? But then you had to copy 'dad' to 'lookup':

       strcpy(lookup, dad.c_str());

However, that might crash if dad's name has more than 14 characters. So, better take string ...

Hope, that helps

Alex





Avatar of jandhb

ASKER

Alex, that is a lot of information for me at this point, but nonetheless very good. I think I follow class declaration code, so were good there. However, the family.cpp file where these functions are being declared I need some help and also with the family_prog.cpp file. Here is what I have in the family.cpp file. I know it is not correct, but can you show me what i need and kind of explain what is going on in the process. A lot of this is new to me, so I apologize for the beginner questions and requests.

--------------------------------
#include <iostream>
#include "family.h"
#include <string.h>
using namespace std;

string family::getFather()

{
      Family myFamily("Smith", "Bob", "Mary");
  string dad = myFamily.getFather();
   vector<string> children;
  children.push_back("Heather");
}

for (index=0; index < children.size(); index++)
{
      vector<string> members;
      members.push_back("John");
      members.push_back("Heather");
      for (int index=0; index < members.size(); index++)
      {
            if (members[index] == dad)
                  break;
      }
}
-----------------------------------------
And then in the family_prog.cpp I still have...
#include <iostream>
#include "family.h"
#include <string>
using namespace std;


void main (void)
{
      family member;
      string dad;
      cout<<"Who is the dad?";
      cin >> dad;
      cout<<"His child is then " <<member.getName(dad);
}
------------------------------------

Thanks for your help.
Justin

 
>> #include <string.h>

string.h is old C header, you have to use

#include <string>

to get STL std::string class.

>> string family::getFather()

I changed the class name from 'family' to 'Family' as it is common to use capital letters for private classes. Also,  if variables begin with lower case letter, you may have a variable called 'family' not confusing with the class name. However, it's your choice. If you follow me the implementation is:

 string Family::getFather()
 {
      return father;   // it simply returns a copy of the data member 'father'
 }

All other get functions are as simple as the one before:

string Family::getFamilyName()
 {
      return familyName;   // it simply returns a copy of the data member familyName
 }

vector<string>& Family::getChildren()
{
     return children;   // here we return a reference of data member 'children' and not a copy      
}

You need an implementation of all member functions of class Family including the constructors:

     // default constructor
     // all data members are empty
     Family::Family()  
     {
     }
     
     // constructor taking family name, father and mother
     Family::Family(const string& name, const string& dad , const string& mom)
     : familyName(name), father(dad), mother(mom)     // That is called initializer list; the data members
                                                                                // get their initial value from the arguments
     {
     }

     // Note, that i changed argument from 'familyName' to 'name' avoiding being same as data member
     void Family::setFamilyname(const string& name)
     {
           familyName = name;
     }

     void Family::setFather(const string& dad)
     {
          // to do
     }
     void Family::setMother(const string& mom)
     {
          // to do
     }
     void Family::addChild(const string& child)
     {
           children.push_back(child);       // appends child name to end of array
     }

     string Family::getChild(int i)
     {
          if (i < 0 || i >= children.size())
              return "???";
          return children[i];
     }


All your implementation from above, you should move to main()

#include "family.h"

#include <iostream>
#include <string>
#include <vector>

using namespace std;


void main (void)
{
     Family myFamily("Smith", "Bob", "Mary");
     string dad = myFamily.getFather();    // dad = "Bob";
     myFamily.addChild("Heather");          // Heather is oldest child
     myFamily.addChild("Michael");          // Michael is 'middle'
     myFamily.addChild("Leila");               // Leila is youngest

     // have a local array to collect all family members
     vector<string> members;
     members.push_back(dad);                                      // insert father as first member
     members.push_back(myFamily.getMother());           // insert mother as second member

     vector<string>& children = myFamily.getChildren();   // we got a reference of the children member array

     // copy all children to members array
     for (int index=0; index < children.size(); index++)
     {
          members.push_back(myFamily.getChild(index));    // add child to members array
     }
     
     while (true)
     {
        string name;
        cout<< "Enter a first name [or 'quit' to exit] ";
        cin >> name;
        if (name == "quit)
           return;

         bool found = false;
         for (int index=0; index < members.size(); index++)
         {
            if (members[index] ==name)
            {
               found = true;
               break;
            }
         }

         if (found)
             cout << name << " is a member of my family " << endl;
         else
            cout << name << "???, never heard. " << endl;
       }
}

You, see in the class there are only variables and no text constants like "Heather". Real life names we use only in the test program.

You may easily improve the test prog by asking for all names of the family. Ask for the children in a separate loop that could be stopped by entering 'next'. Add new data members grandpa and grandma ... If you feel comfortable with this, create a new class FamilyMember, having data members  name, sex, age, a default constructor and a full constructor, get and set functions for all data members. If done, change all string members of class Family to FamilyMembers ...

Regards, Alex

Regards, Alex







Avatar of jandhb

ASKER

alex, can i send you my three files and have you take a look at what i have and why i am still getting some errors? Or do you have msn messenger?
thanks for all your help.

justin
If they are not too big just post them here on EE.

or send them by e-mail to info@sbsweb.info.

Regards, Alex
Ok, they are workingnow. You should try to get an editor that doesn't make word wrapping beyond of 80 chars/line. And some 'todos' where also missing ;-)

// ------------------- family.cpp -------------------------------------------------
#include <iostream>
#include "family.h"
#include <string>

// string.h is an old c header and i should use #include <string>
// to get the STL std::string class/to use string family::getfather()

using namespace std;


//common to use capital letters for private classes.

string Family::getFather()
{
   return father;   // it simply returns a copy of the data
                         // member 'father'
}

string Family::getMother()
{
   return mother;   // it simply returns a copy of the data
                           // member 'mother'
}

//All other get functions are as simple as the one before:

string Family::getFamilyName()
{
   return familyName;   // it simply returns a copy of the data
                                  // member familyName
}

vector<string>& Family::getChildren()
{
   return children;   // here we return a reference of data member
                            // 'children' and not a copy
}

// You need an implementation of all member functions of class
// Family including the constructors:

// default constructor
// all data members are empty
Family::Family()
{
}

// constructor taking family name, father and mother
Family::Family(const string& name, const string& dad , const string& mom)
: familyName(name), father(dad), mother(mom)    
                                    // That is called initializer list; the data members
                                    // get their initial value from the arguments
{
}

// Note, that i changed argument from 'familyName' to 'name' avoiding
// being same as data member
void Family::setFamilyname(const string& name)
{
   familyName = name;
}

void Family::setFather(const string& dad)
{
  father = dad;
}
void Family::setMother(const string& mom)
{
  mother = mom;
}
void Family::addChild(const string& child)
{
  // appends child name to end of array
   children.push_back(child);  
}

string Family::getChild(int i)
{
  if (i < 0 || i >= children.size())
      return "???";
  return children[i];
}

// ------------------------------- family.h ------------------------------------

#ifndef family_h
#define family_h
#include <string>
#include <vector>
using namespace std;

//family class declaration
class Family
{
private:
    string familyName;
    string father;
    string mother;
    vector<string> children;
public:
    Family();
    Family(const string& familyName, const string& dad , const string&
        mom);
    void setFamilyname(const string& familyName);
    void setFather(const string& dad);
    void setMother(const string& mom);
    void addChild(const string& child);
    string getFamilyName();
    string getFather();
    string getMother();
    string getChild(int i);
    vector<string>& getChildren();
};
#endif

// ----------------------------- family_prog.cpp ------------------------------------

#include "family.h"
#include <iostream>
#include <string>
#include <vector>

using namespace std;


void main (void)
{
    Family myFamily("Smith", "Bob", "Mary");
    string dad = myFamily.getFather();  
    // dad = "Bob";
    myFamily.addChild("Heather");                          
    // Heather is oldest child
    myFamily.addChild("Michael");      
    // Michael is 'middle'
    myFamily.addChild("Leila");
    // Leila is youngest
   
    // have a local array to collect all family members
    vector<string> members;
    // insert father as first member
    members.push_back(dad);                            
    // insert mother as second member
    members.push_back(myFamily.getMother());                
    // we'll get a reference of the children member array
    vector<string>& children = myFamily.getChildren();      
   
    // copy all children to members array
    for (int index=0; index < children.size(); index++)
    {
        members.push_back(myFamily.getChild(index));        // add child to members array
    }
   
    while (true)
    {
        string name;
        cout<< "\nEnter a first name [or 'quit' to exit] ";
        cin >> name;
        if (name == "quit")
            return;
       
        bool found = false;
        for (int index=0; index < members.size(); index++)
        {
            if (members[index] ==name)
            {
                found = true;
                break;
            }
        }
       
        if (found)
            cout << name << " is a member of my family " << endl;
        else
            cout << name << "???, never heard. " << endl;
    }
}

// --------------------- end of source -------------------------------------------


I would recommend you to increase points and post the questions of your mail here in EE, maybe in a new thread?

Regards, Alex


Avatar of jandhb

ASKER

Alex,

1. I increased the points to 100.
2. I'm getting 7 warnings that all look similar in family.cpp, i think...
--------------------------------
c:\program files\vc98\include\vector(39) : warning C4786: 'std::reverse_iterator<std::basic_string<char,std::char_traits<char>,std::allocator<char> > const *,std::basic_string<char,std::char_traits<char>,std::allocator<char> >,std::basic_string<char
,std::char_traits<char>,std::allocator<char> > const &,std::basic_string<char,std::char_traits<char>,std::allocator<char> > const *,int>' : identifier was truncated to '255' characters in the debug information
        c:\program files\vc98\include\vector(39) : while compiling class-template member function '__thiscall std::vector<std::basic_string<char,std::char_traits<char>,std::allocator<char> >,std::allocator<std::basic_string<char,std::char_traits<cha
r>,std::allocator<char> > > >::std::vector<std::basic_string<char,std::char_traits<char>,std::allocator<char> >,std::allocator<std::basic_string<char,std::char_traits<char>,std::allocator<char> > > >(const std::allocator<std::basic_string<char,std::
---------------------------------
3. What function(s) hold the names of the dads and the children, so I can populate them with the correct data. Now when I enter a name it simply returns not found. Where is that data being held?

Thanks.
char_traits<char>,std::allocator<char> > > &)'

Avatar of jandhb

ASKER

Ok, I think I where to add the father's name - Family myFamily("Jerry", "John", "Kent");

However, it seems that the first name can't be found. For example, if I would type in "Jerry" it would say, never heard, but "John" works.

I want the program to return the children for each father. It does not seem to be doing that. Do I need to tell it to go to a certain function in order to display the children if the dad's name is found? Right now it is just saying ..... "is a member of my family."
You can ignore warnings as they are in debug mode only. STL names become longer than 255 characters what is the maximum VC Debugger supports.

You may suppress warnings by inserting this pragma statement as first line to your cpp files:

#pragma warning ( disable : 4786 )

Note, spaces in this statement are necessary.

The answer to your next question will come soon.

Regards, Alex
ASKER CERTIFIED SOLUTION
Avatar of itsmeandnobodyelse
itsmeandnobodyelse
Flag of Germany image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial