《C++ Primer Plus》学习笔记5

《C++ Primer Plus》学习笔记5

第10章 对象和类
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
1、抽象和类(类是用户定义的类型,对象是类的实例)
1)指针需要的内存数量很可能和int相同,甚至可能在内部被表示为整数,但不能对指针执行与整数相同的运算,因为C++中没有这个运算,这样做没有意思。
2)指定基本类型完成下面三项工作
①决定数据对象需要的内存数量
②决定如何解释内存中的位
③决定可使用数据对象执行的操作或方法。
3)定义类 类规范由两个部分组成
①类声明:以数据成员的方式描述数据部分,以成员函数的方式描述公有接口(类声明描述了类的蓝图)
②类方法定义:描述如何实现类成员函数(方法定义则提供了细节
4)类

//关键字class标识类定义
class Stock
{
//关键字private标识只能通过公共成员函数访问类成员
    private:
        char company[30];//类成员可以是数据类型,也可以是函数
        int shares;
        double share_val;
        double total_val;
        void set_tot()
            {
                total_val = shares * share_vail;
            }
    //关键字public识别组成类的公共接口的类成员(抽象)
    public:
    void acquire(const char * co, int n, double pr);
    void buy(int num, double price);
    void sell(int num, double price);
    void update(double price);
    void show();
}

5)类的设计尽可能将公共接口与实验细节分开,公有接口表示设计的抽象组件,将实验细节放在一起并将他们与抽象分开被称为封装。
控制对成员的访问,无论类成员是数据还是成员函数,都可以在类的公有部分或私有部分中声明它,但由于隐藏数据是OOP的主要目标之一,因此数据项通常放入私有部分,这叫做数据隐藏,组成类接口的成员函数放入公有部分,这叫做公有接口;否则无法从函数中调用这些函数。
6)在类声明中,我们可以不必使用关键字private,因为这是类对象的默认访问控制。

class World
{
    float mass;
    char name[20];
public:
    void tellall(void);
    ……
};

7)类和结构的区别,结构的默认的访问类型是public,而类为private。C++程序员通常使用类来实现类描述,而把结构限制为只表示纯粹的数据对象货没有私有部分的类。
8)实现类成员的函数
①成员函数定义和常规函数定义非常相似,它们有函数头和函数体,也可以有返回类型和参数,但还有两个特殊的特征:定义成员函数时,使用作用域解析操作符(::)来标识函数所属的类;类方法可以访问类的private组件
②内联方法:其定义位于类声明中的函数都将自动成为内联函数,类声明常将短小的成员函数作为内联函数,其实也可以爱类声明之外定义成员函数,并使其成为内联函数,只需要在类实现部分中定义函数时使用inline限定符

//set_tot()就满足这样的要求
class Stock
{
    private:
        ……
        void set_tot();
    public:
        ……
};

inline void Stock::set_tot()
{
    total_val = shares * share_val;
}

2、类的构造和析构函数
1)切记不要将类成员的名称用作构造函数的参数。构造函数的参数表示的不是类成员,而是赋给类成员的值,参数名不能与类成员相同,否则最终会出现shares = shares。所以我们往往会在数据成员名中加上_m前缀。

class stock
{
    private:
            string m_company;
            int m_shares;
            ……
}

2)使用构造函数
Stock food = Stock("World Cabbage", 250, 1.25); //显式调用
Stock garment("Furry Mason", 50, 2.5); //隐式调用
3)每次创建一个类对象,C++都将使用类构造函数
Stock *pstock = new Stock("Electroshock Games", 18, 19.0);
构造函数的使用方式不同于其他类的方式,用对象来调用方法
stock1.show();
但无法使用对象调用构造函数,因为在构造函数构造出对象之前,对象是不存在的,所以构造函数是用来创建对象的,而不能通过对象来调用。
4)析构函数(每个类只能有一个析构函数)
①用析构函数创建对象后,程序负责跟踪对象,直到其过期为止,对象过期时,程序会自动调用一个特殊的成员函数。这个函数就叫做析构函数,析构函数完成清理的工作。
如果构造函数使用new来分配内存,则析构函数使用delete来释放这些内存,如果构造函数没有使用new,那么析构函数实际上没有需要完成的任务。
②析构函数的名称很特殊,在类名前加上~,因此Stock类的析构函数为~Stock(),而且和构造函数一样,析构函数没有返回值和声明类型,和构造函数不一样的是,析构函数没有参数。

Stock::~Stock()
{

}
//为了让读者看出析构函数何时被调用
Stock::~Stock()
{
    cout << "Bye, " << company << "!\n";
}

③什么时候调用析构函数呢?
通常不在代码中显式地调用析构函数,
如果创建的是静态存储类对象,则析构函数将在程序结束时自动被调用;
如果创建的是自动存储类对象,则析构函数将在程序执行完代码块时被自动调用;
如果对象是new创建,则将驻留在堆栈内存或自由存储区中,当使用delete来释放内存时,其析构函数将自动被调用。

Stock stock2 = Stock("Boffo Objects", 2, 2.0);
stock1 = Stock(“Nifty Foods”, 10, 50.0);

第一条语句是初始化,它创建有指定值得对象,可能会创建临时对象,也可能不会;
第二条语句是赋值,使用析构函数总会导致在赋值前创建一个临时对象。
⑤只要类方法不修改调用对象,就应将其声明为const。
5)补充:

Stock hot = {"Sukie's Autos, Inc. ", 200, 50.25};//编译错误
Classname object = value;// 接受一个参数的构造函数允许使用赋值句法来将对象初始化为一个值。

3、this指针
1)要对Stock对象stock1和stock2进行比较,并且将其中股价总值较高的哪一个赋给top对象,可以使用下面三种方法:

top = stock1.topval(stock2);//显式访问stock2
top = stock2.topval(stock1);//显式访问stock1
const Stock & Stock::topval(const Stock & s)const
{
    if(s.total_val > total)
        return s;
    else
        return *this;//意味着返回的是调用对象本身,而不是拷贝
}

2)每个成员函数都有一个this指针,this指针指向调用对象,要引用整个调用对象,则可以使用表达式*this,在函数括号后面使用const限定符将this限定为const,这样将不能使用this来修改对象的值。this指针被设置为调用对象的地址,加上符号的this是对象的别名

kate.topval(joe);
// 使用kate来调用topval(),因此s是joe,this指向kate,*this是kate

4、对象数组
声明对象数组:
Stock mystuff[4];
每一个元素mystuff[0]、mystuff[1]等都是Stock的对象
如果类中包含多个构造函数,则可以对不同的元素使用不同的构造函数

const int STKS = 10;
Stock stocks[STKS] = 
{
    Stock("NanoSmart", 12.5, 20),
    Stock(),
    Stock(“Monolithic Obelisks”, 130, 3.25),
};

代码中使用常规格式定义了stock[0]和stock[2],使用stock()构造函数来初始化stock[1],剩余的7个元素将使用默认构造函数进行初始化。
初始化对象数组的方案是,首先使用默认构造函数创建数组元素,之后花括号中的构造函数将创建临时对象,之后将临时对象的内容复制到相应的元素中,因此要创建类对象数组,这个类必须要有默认构造函数。
5、接口和实现小结
如果数组长度超过限制的时候,我们可以采用两个处理方法,方法一是增加数组的长度,这样会导致空间的浪费;方法二是使用string而不是字符数组。
6、类作用域
函数名称作用域是全局的,但不能全部是局部的,C++类引入了一种新的作用域,叫做类作用域

class Stock
{
    private:
        const int len = 30;
        char company[len];
        ……
}

这是不对的,因为声明类只是描述了对象的形式,并没有真正创建对象,我们可以采用下面方法:
①在类中声明一个枚举,在类声明中声明的枚举的作用域时整个类,因此可以用枚举为整数常量提供作用域为整个类的符号名称

class Stock
{
    private:
        enum{Len = 30};
        char company[Len];
        ……
}

用这种方式声明的枚举并不会创建类数据成员,也就是说,所有对象中都不包含枚举,Len只是一个符号名称,在作用域为整个类的代码中遇到它时候,编译器将用30来替换它。
②C++引入了另一种在类中定义常量的方式,使用关键字static

class Stock
{
privatestatic const int Len = 30;
    char company[Len];
    ……
}

创建一个名为Len的常量,该常量将与其他静态变量存储在一起,而不是存储在对象中,只有一个Len常量,它被所有的Stock对象共享。
7、抽象数据类型
1)通过使用堆栈可以以这样的方式存储数据,即总是从堆顶添加或删除数据,C++程序使用堆栈来管理自动变量,当新的自动变量被生成后,它们被添加到堆顶,消亡时从堆栈中删除它们。
2)堆栈由可对它执行的操作来描述
①可创建空堆栈
②可将数据项添加到堆顶(压入)
③可从栈顶删除数据项(弹出)
④可查看堆栈是否填满
⑤可查看堆栈是否为空

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<,完结于2014.7.18 22:18

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值