You are here:

C++/only 2 questions

Advertisement


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

class Animal{
  protected:
     char desc[20];
     float height,weight;
  public:
     Animal(char[],float,float);
  };

class Bird:public Animal{
  private:
     float wingspan;
  public:
     Bird(char[],float,float,float);
     float getheig();
  };

Animal::Animal(char de[],float heig,float weig){
  strcpy(desc,de);
  height = heig;
  weight = weig;
}

Bird::Bird(char de[],float heig,float weig,float wingsp)
     :Animal(de,heig,weig){
        wingspan=wingsp;
     }


Define a class called Animal
        Desc : array of 20 characters
        weight : float
Define a class Bird that inherits from Animal class above
        Wingspan : float
The program that above is correct or not?

How can I write below (in C++)?
I only do not know how can I write (below)?
Thanks!

My program should be able to store up to 10 BirdRec records in an array called BirdsArray.

And has some operations(e.g Add new bird records into BirdArray)  

Answer
First off, did you try to compile the code? Any mistakes in the use of the language would be picked up by the compiler - at least to the extent of the compiler's compliance with the ANSI/ISO C++ standard - some are better than others. In any case no matter whether the code is correct or not you still have to get it past the compiler you are using even if it is broken with regard to standard C++.

Anyhow the very first lines are incorrect - standard C++ has no such header files as iostream.h, string.h or conio.h. The first is the old name for iostream (no .h extension). string.h is the C header file for C string utility function declarations - so this is not totally incorrect, however C++ renames it to be cstring (again no .h extension). conio.h is a largely Microsoft invention - although I believe other compiler vendors such as Borland may also supply a version, at least on MS Windows platforms - so this header can only be used with compilers which support it and its contents may of course vary as it is non-standard.

The only reason for using iostream.h and string.h is if your code is compiled with an old compiler that does not support the new header files and the standard C++ library and I would urge you to locate a more up to date implementation such as the current GNU compiler release or one of the MS Windows compilers based on it such as Mingw and the Dev-C++ integrated development environment (see http://www.bloodshed.net/download.html). Note these are free and often used by people learning C++.

The second point is that the only header file you require at the moment is the second one string.h or, in C++, cstring - for strcpy. I found all this out by running your code through a compiler and commenting out the header files until things broke.

However, having replaced the three header file includes with just one for cstring (or string.h) you code compiles.

Next, I must point out that the style you are using for your code layout is outdated, often used in books and magazine articles to save space and is generally considered to render the code unclear. Try doing something more like this - although this is only one possibility:

class Animal
{
protected:
  char desc[20];
  float height, weight;
public:
  Animal(char[],float,float);
};

and

Animal::Animal(char de[],float heig,float weig)
{
  strcpy(desc,de);
  height = heig;
  weight = weig;
}
Next you seem to understand the use of an initialiser list for initialising base classes using a constructor other than the default constructor but you do not extend this to the individual class members. The only exception is the call to strcpy (which I will return to later) to initialise desc. You could for example rework the Animal class constructor like so:

Animal::Animal(char de[],float heig,float weig)
: height( heig )
, weight( weig )
{
  strcpy(desc,de);
}

Note this layout is my preferred style but you may prefer the more common ones such as:

Animal::Animal(char de[],float heig,float weig)
: height( heig ),
 weight( weig )
{
  strcpy(desc,de);
}

or

Animal::Animal(char de[],float heig,float weig)
: height( heig ), weight( weig )
{
  strcpy(desc,de);
}

Now I notice you seem to like to bunch everything up and not give information just because it is optional - such as names for parameters in function declarations. Don't. Space your code out so it can be easily read by people - in most real life projects 80% of the time is spent maintaining the code - which means it needs to be read and understood to allow updates and fixes to be applied often years after it was originally written and by people other than the person who wrote it. Common practice then is in general to not place many member or object definitions on one line as in the case from class Animal:

  float height, weight;

but to place them one per line like so:

  float height;
      float weight;

and not to leave out names of parameters in function declarations:

  Animal(char[],float,float);

But to add them in:

  Animal( char de[], float heig, float weig );

This in fact has another boon in that function declarations and definitions look similar, however of course for member functions you need to add the class qualifier to the function name. The boon is that you can copy and paste the declaration, remove the semi colon and add the class names qualifier if necessary and off you go. No need to type it all from scratch.

You are using arrays of char. Again this may be because your C++ implementation does not have the std::string class - again try and update your implementation if possible. Using std::string in place of arrays of char would simplify the code further as there is no need to copy std::string objects using special functions as is the case with C-strings and strcpy - they can be initialised as the other members.

Now to naming. You tend to contract names - in fact you have to change the names of parameters to the constructors so as not to clash with the member names. The worst example is getheig member function - why not getheight or get_height or GetHeight?

Now one popular convention is to prefix or postfix member names with a letter or character so they can be easily differentiated from non-members in member functions. Common examples are m or m_ prefixes for member or i prefix for instance member or an trailing underscore (prefixed underscores are reserved for use by C++ implementations). Here is the Animal class member height renamed using these conventions:

       mHeight
       m_height
       iHeight
       height_

Note that I add capitalisation if the prefix would obscure the name of the member. A side effect is that names of constructor parameters can if required now be the same as the member names they are to initialise less the prefix or postfix.

Now the next thing I notice is that Bird contains a member function getheig to presumably return the height of the bird. However height is an attribute of Animal, the base of Bird - so why can we not get the height of all types of Animals, not just Birds?

To put it another way: why does a sub-class get an attribute of its base class? Why is this getter not a member of the base class?

Which leads on to the next point. Why are sub classes allowed direct access to the base class data? Do they need it? If they do provide exactly the accessor (setters and getters) that are required and make them protected or public if anyone should be able to access the information.

Taking all the points made so far and making a couple of style choices your original code looks like this:

#include <string> // for C++ std::string class

class Animal
{
private:
  std::string   m_desc;
  float    m_height;
      float    m_weight;

public:
  Animal( std::string const & desc, float height, float weight );

  float get_height() const;
};

class Bird : public Animal
{
private:
  float      m_wingspan;

public:
  Bird( std::string const & desc
       , float height
       , float weight
       , float wingspan
       );
};

Animal::Animal( std::string const & desc, float height, float weight )
: m_height( height )
, m_desc( desc )
, m_weight( weight )
{
}

Bird::Bird
( std::string const & desc
, float height
, float weight
, float wingspan
)
: Animal( desc, height, weight )
, m_wingspan( wingspan )
{
}

int main()
{
}

Of course your original code did compile - once I had tidied up the header files includes - and probably as far as I could see would work - the biggest gripe being the placement of getheig - so you can choose to mostly ignore what I have said so far. Also due to your use of tabs and tabs spacing varying from editor to editor some parts of the code listed above may not be arranged for you quite as I intended.

As to the Bird array - well I think I did in fact answer that for you in what I think was your previously question - sorry if it was someone else. The most obvious and most in keeping with the C with a bit of C++ style of the code is to use a built in array of 10 Bird objects:

       int const MaximimBirdRecords(10);

   // ...

       Bird birdRecords[MaximimBirdRecords];

However to achieve this you need to provide the Bird class with a default constructor - that is one that can be called with no parameters, leaving the object in a default state.

Of course you could also use a std::vector, if it is available in your C++ implementation (if not again get something more up to date...):

       #include <vector>

   // ...

   // Convenience alias for std::vector of Bird objects:
       typedef std::vector<Bird>  BirdVector;


   // ...
       
       BirdVector birdRecords;

Which will allow for more than 10 records as it automatically expands the size of the vector as more objects are added but you can always add code to check for the maximum allowed and stop any more being added - code you would need for the built in array case anyway to prevent overrunning the end of the array and possibly overwriting memory that you should not or causing the program to crash with a memory access violation due to the attempt.

Note that I am not going to go into great detail on std::vector here but leave that for you to look into if you are interested. As I stated before that in order to use a type as the element type of a std::vector class it must be a good citizen - which for the C++ standard library container types means it must be copyable - which in some cases requires the provision of a special constructor called a copy constructor - the compiler will generate one for a class if it does not provide one and this will do for many but not all cases. Likewise, it must be assignable ( element1 = element2 ), and again the compiler generated assignment operator ( operator= ) may not do for all cases. Finally it must be destroyable by a destructor - again the compiler will generate one for a class. In this case once again I think you are OK.

To add a new Bird to the array:

       BirdVector birdRecords;
   // ...
       Bird a_bird("pideon", 10, 200, 0.5);

   // makes copy of a_bird in birdRecords
       birdRecords.push_back( a_bird );


or more briefly:

       birdRecords.push_back( Bird("pideon", 10, 200, 0.5) );

Of course adding birds to the bird vector (or array) is an operation on the vector, not the Bird class itself. So it might be an idea to wrap the vector of birds in its own class and give it its own operations.

I would have thought that your tutor would should have given you the information you require for you to complete the task or the notes or books your are following would have explained what you need to know if you are on your own.

I do not have the time to teach you what you should have picked up from your studies - such as writing classes and member functions of those classes - you obviously have some idea what to do as you presented me with some plausible code. As you see just this little question has taken seven pages!  

C++

All Answers


Answers by Expert:


Ask Experts

Volunteer


Ralph McArdell

Expertise

I am a software developer with more than 15 years C++ experience and over 25 years experience developing a wide variety of applications for Windows NT/2000/XP, UNIX, Linux and other platforms. I can help with basic to advanced C++, C (although I do not write just-C much if at all these days so maybe ask in the C section about purely C matters), software development and many platform specific and system development problems.

Experience

My career started in the mid 1980s working as a batch process operator for the now defunct Inner London Education Authority, working on Prime mini computers. I then moved into the role of Programmer / Analyst, also on the Primes, then into technical support and finally into the micro computing section, using a variety of 16 and 8 bit machines. Following the demise of the ILEA I worked for a small company, now gone, called Hodos. I worked on a part task train simulator using C and the Intel DVI (Digital Video Interactive) - the hardware based predecessor to Indeo. Other projects included a CGI based train simulator (different goals to the first), and various other projects in C and Visual Basic (er, version 1 that is). When Hodos went into receivership I went freelance and finally managed to start working in C++. I initially had contracts working on train simulators (surprise) and multimedia - I worked on many of the Dorling Kindersley CD-ROM titles and wrote the screensaver games for the Wallace and Gromit Cracking Animator CD. My more recent contracts have been more traditionally IT based, working predominately in C++ on MS Windows NT, 2000. XP, Linux and UN*X. These projects have had wide ranging additional skill sets including system analysis and design, databases and SQL in various guises, C#, client server and remoting, cross porting applications between platforms and various client development processes. I have an interest in the development of the C++ core language and libraries and try to keep up with at least some of the papers on the ISO C++ Standard Committee site at http://www.open-std.org/jtc1/sc22/wg21/.

Education/Credentials

©2016 About.com. All rights reserved.