Member Functions

You have already seen member functions (sometimes called methods) being used. For instance, string has a find() method, which is called using the dot (.) operator. When defining structures, you defined member variables; it is now time to see how to define member functions.

Putting Functions inside Structures

Consider the Point structure from Chapter 5, “Structures and Pointers,” which consists of two fields, representing the x and y coordinates of a point. In Chapter 5 we defined the function make_point(), which generates points in a convenient way. A common property of points is their length, defined as the distance from the origin—(0,0)—to the point (x,y). These two points define the corners of a triangle, so the Pythagoras theorem gives the length of this line as the square root of the sum of the sides squares. Instead of making these ordinary functions, you can put them inside a struct, as follows:

int sqr(int x)  {  return x*x; }

struct Point {
  int x,y;

  void set(int xp, int yp) {
    x = xp;
    y = yp;
  }

  int length()  {
   return sqrt(sqr(x) + sqr(y));
  }

 };

;> Point p;
;> p.set(10,10);
;> p.length();
(int) 14

Any function defined inside a struct is called a member function, or a method. You call a member function by using the dot operator, in the same way you call the methods of standard library objects, such as string. So all struct members—variables or functions—are accessed in the same way: p.x, p.length(), and so on.

Note that you can use any other members within the member function definition without using the dot operator! In the member function set(), the member variables x and y are available directly (as if they were global variables), but of course you could hide them by accident. This is why the preceding example calls the arguments of set() xp and yp. The method length() has no explicit arguments: The object is completely implicit.

In most C++ implementations, the object is passed as a hidden reference parameter, so the call p.length() is actually equivalent to something like length(p). Otherwise, member functions behave like ordinary functions; they can be overloaded, take default arguments, call themselves recursively, and so on.

The following example adds another function, called set(), to the structure shown in the preceding example:

struct Point {
  ...
  void set(int val=0) {
    set(val,val);
  }
};
;> p.set(0,0);  // calls the first version of set() with two arguments
;> p.set(0);    // calls the second version of set() with one argument
;> p.set();     // second version, w/ default argument of 0
						

set() takes one argument and calls the first set() method to do the actual work (this isn't recursion!) The first set() is a member of Point and so can be accessed directly. Again, we don't need the dot operator since the object is implied.

NOTE

In this example, you could use x = val; y = val, but this example shows you how one member function can call another, without using the dot operator.


Why would you want to put functions inside structures? For one thing, it simplifies code because you can simply use x instead of p.x, and you don't have to explicitly pass the object. But the main reason to put functions inside structures has to do with how we think about data; length(p) means “calculate the length of p,” whereas p.length() means “ask p for its length.” The object p becomes responsible for supplying its length to any interested customer, or client.

NOTE

With more complicated situations than this example, it is important to have a naming convention. You must be able to tell at a glance whether a variable is a member or just local to a function; I tend to prefix member variables with m_ (for example, m_x, m_y), but you can choose any scheme, as long as you're consistent.


Public and Private Members

Object-orientation makes objects responsible for looking after their own data. An analogy is an employee who is delegated a task; the boss does not want to know the details—only that the job is done. Employees need privacy to function; you can't expect them to do a good, responsible job if people keep popping in and replying to their e-mail and writing on their papers. You can mark data and functions as being private within a struct. Here is a simplified definition of a Person struct:


struct Person {
  private:
    string m_name;
    long   m_phone;
    string m_address;
    long   m_id;
  public:
    void set(string name, string address, long phone, long id) {
       m_name = name;   m_address = address;
       m_phone = phone; m_id = id;
    }

    string get_name()     { return m_name; }
    string get_address()  { return m_address; }
    long   get_phone()    { return m_phone;  }
    void   set_phone(long ph) { m_phone = ph; }
    long   get_id()       { return m_id;     }
 };
;> Person eddie;
;> eddie.set("Eddie","",6481212,554433);
;> eddie.get_name();
(string) 'Eddie'
;> eddie.m_name;
CON 11: Cannot access 'm_name'
(string) 'Eddie'

The Person object has some privacy to manage its own data. Any code outside the structure cannot access the member variables directly. My attempt to directly access eddie.m_name produced an error message, since m_name is declared private to Person. To modify m_name, outside code has to go through the proper channels and use the accessor functions such as get_name(). Accessor functions are often called get and set methods.

Notice that all members after private: will be private to the struct, until a public: statement is encountered. In Java, each member has to be explicitly marked public or private.

struct and class

At this point, we will begin to use the keyword class instead of the keyword struct. The resulting type is exactly the same; the only serious difference between struct and class is that classes are private by default and you always have to use public: to make your members visible to the rest of the world. Generally, member variables are kept private, and you define get and set methods for public access.

This seems at first to be both fussy and inefficient, but C++ does not penalize you for this programming style. When you write methods inside the class body (that is, everything in the braces following class), the compiler tries to inline them. That is, the machine code is directly injected in place of a function call. If the function is a simple one, such as a member variable access function (for example, get_id() in the Person class above), then this is just as efficient as accessing the variable directly. That is, eddie.get_id() is likely to be just as fast as eddie.m_id. In general, you should not worry about the extra cost of making a function call until you know for sure that the cost is unacceptable.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.227.10.45