C++ primer plus 第十章 对象和类

重要的面向对象编程特性:抽象、封装和数据隐藏、多态、继承和代码的可重用性。为了实现这些特性并将它们组合在一起,C++所做的最重要的改进是提供了类。

类是一种将抽象转换为用户定义类型的C++工具,它将数据表示和操纵数据的方法组合成一个整洁的包。

类声明:以数据成员的方式描述数据部分,以成员函数(被称为方法)的方式描述公有接口。

类定义:描述如何实现类成员函数。

通常,C++程序员将接口(类定义)放在头文件中,并将实现(类方法的代码)放在源代码文件中。

1.访问控制

关键字private、public和protected描述了对类成员的访问控制,使用类对象的程序都可以直接访问公有部分,但只能通过公有成员函数(或友元函数)来访问对象的私有成员。

封装:类设计尽可能将公有接口与实现细节分开。公有接口表示设计的抽象组件。将实现细节放在一起并将它们与抽象分开被称为封装。

不必在类声明中使用关键字private,因为这是类对象的默认访问控制。(结构的默认访问类型是public,而类为private)

成员函数定义与常规函数定义非常相似,它们有函数头和函数体,也可以有返回类型和参数。但是它们还有两个特殊的特征:(1)定义成员函数时,使用作用域解析运算符(::)来标识函数所属的类;(2)类方法可以访问类的private组件。

2.内联方法

其定义位于类声明中的函数都将自动成为内联函数,类声明常将短小的成员函数作为内联函数。在类声明之外定义成员函数,并使其成为内联函数,只需在类实现部分中定义函数式使用inline限定符即可。内联函数的特殊规则要求在每个使用它们的文件中都对其进行定义。确保内联定义对多文件程序中的所有文件都可以用、最简便的方法是:将内联定义放在定义类的头文件中。

调用成员函数时,它将使用被用来调用它的对象的数据成员

3.类的构造函数和析构函数

C++提供了一个特殊的成员函数——类构造函数:专门用于构造新对象、将值赋给它们的数据成员。C++为这些成员函数提供了名称和使用语法,而程序员需要提供方法定义,名称与类名相同。

构造函数的参数表示的不是类成员,而是赋给类成员的值。参数名不能与类成员相同,,否则最终的代码将是这样的:

shares=shares;

为避免这种混乱,一种常见的做法是在数据成员名中使用m_前缀:

class Stock
{
 private:
    string m_company;
    long m_shares;
}

另一种常见的做法是,在成员名中使用后缀_:

class Stock
{
private:
    string compant_;
    long shares_;
}

无论使用哪种做法,都可以在公有接口中在参数名中包含conpany和shares。

3.使用构造函数

C++提供了两种使用构造函数来初始化对象的方式:(1)显示地调用构造函数;(2)隐式的调用构造函数。两种调用等价。

Stock food=Stock("World Cabbage",250,1.25);//显示
Stock food("World Cabbage",250,1.25);//隐式

每次创建类对象(甚至使用new动态分配内存)时,C++都使用类构造函数。下面是将构造函数与new一起使用的方法:

Stock *pstock=new Stock("Electroshock Games",18,19.0);

构造函数的使用方式不同于其他类方法。一般来说,使用对象来调用方法,但无法使用对象来调用构造函数,因为在构造函数构造出对象之前,对象是不存在的。因此构造函数被用来创建对象,而不能通过对象来调用。

默认构造函数是在未提供显示初始值时,用来创建对象的构造函数,默认构造函数灭有参数,因为声明中不包含值。

Stock::Stock(){}

当没有定义任何构造函数时,编译器才会提供构造函数。为类定义了构造函数后,程序员就必须为它提供默认构造函数。如果提供了非默认构造函数,但没有提供默认构造函数,则下面的声明会出错:

Stock stock1;

这样做的原因可能是想禁止创建为初始化的对象,定义默认构造函数的方法有两种:(1)给已有构造函数的所有参数提供默认值;(2)通过函数重载来定义另一个构造函数——一个没有参数的构造函数。)(只能有一个默认构造函数,这两个不能同时使用)

Stock(const string &co="Error",int n=0,double pr=0.0);//(1)
Stock();//(2)

隐式的调用默认构造函数时不要使用圆括号。

4.析构函数

析构函数的名称很特殊:在类名前加上~。和构造函数一样,析构函数也可以没有返回值和声明类型,与构造函数不同的是,析构函数没有参数。每个类只有一个析构函数。如果构造函数使用了new,则必须提供使用delete的析构函数。

5.const成员函数

const Stock land=Stock("Kludgehorn Properties");
land.show();//无法确定,因为调用对象和const一样,不应被修改。但show()无法确保调用对象不被修改

//新语法——保证函数不会修改调用对象
void show() const;//声明
void stock::show() const;//定义
//以这种方式声明和定义的类函数被称为const成员函数。

构造函数是一种特殊的类成员函数,在创建类对象时被调用。构造函数的名称和类名相同,但通过函数重载,可以创建多可同名的构造函数,条件是每个函数的特征标(参数列表)都不同。另外,构造函数没有声明类型。通常构造函数用于初始化类对象,初始化应与构造函数的参数列表匹配。

5.this指针

到目前为止,每个类成员都只涉及一个对象,即调用它的对象,但有时候方法可能涉及到两个对象,在这种情况下需要使用C++的this指针。所有的类方法都将this指针设置为调用它的对象的地址。

void Stock::show() const
{
    cout<<"Company:"<<company
        <<"Shares:"<<shares<<'\n'
        <<"Share Price:$"<<share_val
        <<"Total Worth:$"<<total_val<<'\n';
}
//转换为下面这样的C-风格定义:
void show(const Stock *this)
{
    cout<<"Company:"<<this->company
        <<"Shares:"<<this->shares<<'\n'
        <<"Share Price:$"<<this->share_val
        <<"Total Worth:$"<<this->total_val<<'\n';
}

6.抽象数据类型

抽象数据类型(abstract data type,ADT)以通用的方式描述数据类型,而没有引入语言或实现细节。例如,通过使用栈,可以以这样的方式存储数据,即总是从堆顶添加或删除数据。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

猜你喜欢

转载自blog.csdn.net/CHY1156957638/article/details/85837434