!!!Chapter 12 Classes (12.1 ~ 12.3)

12.1 Class Definitions and Declarations

12.1.1 Class Definitions: A Recap

Most fundamentally, a class defines a new type and a new scope.

Class Members

Each class defines zero or more members. They can be data, function or type definitions.

A class may contain multiple public, private and protected sections.

All members must be declared inside the class; there is no way to add members once the class definition is complete.

Constructors P263

A constructor is a special member function that has the same name as the class. Its purpose is to ensure that each data member is set to sensible initial values.

A constructor should use a constructor initializer list to initialize the data members of the object:

Sales_item(): units_sold(0), revenue(0.0) {}

The constructor initializer list is a list of member names and parenthesized initial values. It follows the constructor's parameter list and begins with a colon.

The parameter list is empty because we are defining the constructor that is run by default, when no initialzer is present. The body is empty because these is no work to do.

constructor always use initializer list to initialize data:

   class Person{
       public:    
           Person(std::string name, std::string addr): _name(name), _addr(addr) {}
       private:
           std::string _name;
           std::string _addr;
   };

Member Functions

Member functions must be declared inside the class, and can be defined inside or outside the class. Functions defined inside the class are inline by default.

Member functions defined outside the class must indicate that they are in the scope of the class. EG.

double Sales_item::avg_price() const
{
  if(units_sold)
    return revenue/units_sold;
  else
    return 0;
}

12.1.2 Data Abstraction and Encapsulation

The fundamental ideas behind classes are data abstraction and encapsulation.

Data abstraction is a programming technique that relies on the separation of interface and implementation.

Encapsulation is a term that describes the technique of combining lower-level elements to form a new, higher-level entity.

Access Labels Enforce Abstraction and Encapsulation

A class may contain zero or more access labels:

  • Members defined in the public section are accessible to all code that uses the type
  • Members defined in private section are accessible to other class members
Each access label specifies the access level of the succeeding member definition. The specified access level remains in effect until the next access label is encountered or the closing right brace of the class body is seen.

The access level of members defined after the open curly of the class and before the first access label depend on how to class is defined:

  • If the class is defined with the struct keyword, then members defined before the first access label are public;
  • If the class is defined with the class keyword, then members are private.

12.1.3 More on Class Definitions

Multiple Data Members of the Same Type

If the class has multiple data members with the same type, these members can be named in a single member declaration.

class Screen{
public:
    // interface member functions
private:
    std::string contents;
    std::string::size_type cursor;
    std::string::size_type height, width;
};

Using Typedefs to Streamline Classes

A class can also define its own local names for types.

class Screen {
public:
    //interface member functions
    typedef std::string::size_type index;
private:
    std::string contents;
    index cursor;
    index height, width;
}

Type names are also controlled by label:

The definition of index is in the public part, so it's accessible.

Member Functions May be Overloaded

A member function overloads only other member functions of its own class.

The same rules apply to overload member functions as apply to plain functions: Two overloaded members cannot have the same number and types of parameters.

Explicitly Specifying inline Member Functions

Member functions that are defined inside the class are automatically treated asinline. But we can also explicitly declare a member function as inline;

//declare a member function as inline
inline char get(index ht, index wd) const;

We can specify that a member is inline as part of its declaration inside the class body. Alternatively, we can specify inline on the function definition that appears outside the class body.  P 437
It is also legal to specify inline both on the declaration and definition.

12.1.4 Class Declarations versus Definitions

A class is completely defined once the closing curly brace appears.

A class may be defined only once in a given source file. When a class is defined in multiple files, the definition in each file must be identical.

By putting class definition in header files, we can ensure that a class is defined the same way in each file that uses it.

It is possible to declare a class without defining it:

class Screen;   //declaration of the Screen class
The declaration sometimes referred to as a forward declaration. After a declaration and before a definition is seen, the type Screen is an incomplete type, which can be used only in limited ways.

Using Class Declaration for Class Members

A data member can be specified to be of a class type only if the definition for the class has already been seen. If the type is incomplete, a data member can be only a pointer or a reference to that class type.

A class cannot have data members of its own type. (A class definition is necessary for data member definition, and class definition is incomplete before the closing curly brace)

But a class is considered declared as soon as its class name has been seen. Therefore, a class can have data members that are pointers or references to its own type:

class LinkScreen{
    screen window;
    LinkScreen *next;
};

12.1.5 Class Objects

Storage is allocated when we define objects, but not when we define types:

class Sales_item{
public:
    //operation on Sales_item objects
private:
    std::string isbn;
    unsigned units_sold;
    double revenue;
};

The above code defines a new type, but does not allocate any storage.

Sales_item item;

The above code define an object, the compiler will allocates an area of storage to contain that object.

Defining Objects of Class Type

We have two ways to define objects of class type:

  • Using the class name directly as a type name
  • Specifying the keyword class or struct, followed by the class name

Sales_item item1;
class Sales_item item2;

The two methods are equivalent, the second method is inherited from C.

Why a class Definition Ends in a Semicolon

A semicolon is required because we can follow a class definition by a list of object definitions. And a definition must end in a semicolon:

class Sales_item {...};
class Sales_item {...} accum, trans;

Ordinarily, it is a bad idea to define an object as part of a class definition.

12.2 The Implicit this Pointer

Member functions may not define the this parameter; the compiler does so implicitly.

The body of a member function may explicitly use the this pointer, but is not required to do so. The compiler treats an unqualified reference to a class member as if it had been mad through the this pointer.

When to Use the this Pointer

There is one case we must explicitly refer this inside a member function: when we need to refer to the object as a whole rather than to a member of the object. EG.P 414

Returning *this

class Screen{
public:
    Screen& set(char);
};

Screen& Screen::set(char c)
{
    contents[cursor] = c;
    return *this;
}

Returning *this from a const Member Function
In an ordinary nonconst member function, the type of this is a const pointer to the class type. We may change the value to which this points but cannot change the address that this holds.

if we create a const member function, then we can put it at the end of a large expression, but we may not put it in the middle:P 442

//legal, the first two functions will return plain reference
//which can be used by display
myScreen.move(4,0).set('#').display(cout);
//illegal, display will return const reference
//which cannot be used by move function
myScreen.display(cout).move(4,0);

We can call multiple functions in one expression, as long as the return type of functions are reference. So that the returned reference will be used to call the next function.

Overloading Based on const

we can overload a function based on whether its const.

A const object will use only the const member function. A nonconst object could use either member, but the nonconst version is a better match.

class Screen {
public:
    Screen& display (std::ostream &os)
                   { do_display(os); return *this}
    const Screen& display (std::ostream &os) const
                   { do_display(os); return *this}
private:
    void do_display(std::ostream &os) const
                   { os << contents; }
};

Now there are two overloaded member functions. The const member function will only be called when we display a const object:

Screen myScreen(5,3);
cosnt Screen blank(5, 3);
myScreen.set('#').display(cout);    //calls non const version
blank.display(cout);                //calls const version

Mutable Data Members

It sometimes happens that a class has a data member we want to modify, even inside a const member function.

A mutable data member is a member that is never const, even when it is a member of a const object.

To declare a data member as mutable, the keyword mutable must precede thedeclaration of member;

class Screen {
public:
    //do something
private:
    mutable size_t access_ctr;
};

12.3 Class Scope

Every class defines its own new scope and a unique type. Even if two classes have exactly the same member list, they are different types.

Using a Class Member

Outside the class scope, members may be accessed only through an object or a pointer using member access operators dot or arrow.

Some members are accessed using the member access operators; others are accessed directly from the class using the scope operator.

Sales_item item;
Sales_item *ptr = &item;
item.units_sold;
ptr->units_sold;

Screen::index a;    //index is a typedef object.

Scope and Member Definitions
Member definitions behave as if they are in the scope of the class, even if the member is defined outside the class body.

EG. we can declare a member function inside the class and define it outside the class.

Parameter Lists and Function Bodies Are in Class Scope

In a member function defined outside the class, the parameter list and member function body both appear after the member name. They are defined inside the class scope, so can use the class members without scope operator! (no need to use Screen::index)

Function Return Types Aren't Always in Class Scope

If the function is defined outside the class body, then the name used for the return type is outside the class scope. If the return type uses a type defined by the class, it must use the fully qualified name:

inline Screen::index Screen::get_cursor() const    //index is the return type
{
    //do something
}

12.3.1 Name Lookup in Class Scope

name lookup means: the process of finding which declaration is matched to a given use of a name.

Common name lookup process:

1. First, look for a declaration of the name in the block in which the name was used. Only names declared before the use are considered.

    先找本身所在的block

2. If the name isn't found, the enclosing scope(s) are searched

    然后找包含本身所在block的大scope(s)

3. If no declaration is found, then the program is in error.

Class scopes obey the same rule, but the definitions are actually process in two phases:

1. First, the member declarations are compiled.

2. Only after all the class members have been seen are the definitions themselves compiled.

Name Lookup for Class Member Declarations

1. The declarations of the class members that appear before the use of the name are considered.

2. If the lookup in step 1 failed, the declarations that appear in the scope which the class is defined, and that appear before the class definition itself, are considered.P 448

Name Lookup in Class Member Definitions

1. Declarations in the member-function local scopes are considered first. (inside the function itself)

2. The declarations for all the class members are considered. (even the member are declared after the member function)

3. The declarations that appear in scope before the member function definition are considered.P 449

When a member is defined outside the class definition, the third step not only considers the declarations in global scope that appear before the definition of class Screen, but also considers the global scope declarations that appear before the member function definition.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值