《C++ primer plus》学习笔记——第十章对象和类

版权声明:问:是谁的心呐???答:我的~~ https://blog.csdn.net/u011436427/article/details/88668120

一、过程性编程和面向对象编程OOP

(1)采用过程性编程方法
在这里插入图片描述
(2)OOP思想
在这里插入图片描述

二、抽象和类

生活中充满复杂性,处理复杂性的方法之一是简化和抽象;
抽象是通往用户定义类型的捷径,在C++中,用户定义类型指的是实现抽象接口的类设计。

1.类型是什么?

(1)不能对指针执行与整数相同的运算。eg:不能将两个指针相乘,这种运算是没有意义的,so,将变量声明为int或float指针时,不仅仅是分配内存,还规定了可对变量执行的操作。

(2)指定基本类型完成了以下的三项工作:
在这里插入图片描述

2.C++中的类

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

(2)接下来的3-5都是围绕着该eg进行的,所以必须得先说明这个eg
在这里插入图片描述

(3)定义类:类范围由两个部分组成:

  • 类声明:以数据成员的方式描述数据部分,以成员函数(or叫方法) 的方式描述公有接口;
  • 类方法定义:描述如何实现类成员函数

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

(4)什么是接口??
在这里插入图片描述
在这里插入图片描述

扫描二维码关注公众号,回复: 5690915 查看本文章

(5)通常,C++程序员将接口(类定义) 放在头文件中,并将实现(类方法) 放在源代码的文件中。
eg如下:
在这里插入图片描述

// stock00.h -- Stock class interface
// version 00
#ifndef STOCK00_H_
#define STOCK00_H_

#include <string>  

class Stock  // class declaration
{
private: 
    std::string company;
    long shares;
    double share_val;
    double total_val;
    void set_tot() { total_val = shares * share_val; }
public:
    void acquire(const std::string & co, long n, double pr);
    void buy(long num, double price);
    void sell(long num, double price);
    void update(double price);
    void show();
};    // note semicolon at the end

#endif

说明:
(a)C++关键字class指出了这些代码定义了一个类设计;
Stock是这个新类的类型名,该声明能够声明Stock类型的变量——称之为对象或者实例。
对于描述函数接口而言,原型就足够了,将数据和方法组合成一个单元是类最吸引人的特性。
eg:
在这里插入图片描述
在这里插入图片描述
(b)访问控制

(i)private,public,公有成员函数是干啥的??
在这里插入图片描述
(ii)封装是干啥的?
在这里插入图片描述

(iii)解释图
在这里插入图片描述

(iiii)OOP和C++之间的关系
在这里插入图片描述
在这里插入图片描述

(iiiii)数据隐藏的好处
在这里插入图片描述

(c)控制对成员的访问:公有还是私有?
(i)注意:使用私有成员函数来处理不属于公有接口的实现细节
在这里插入图片描述

(ii)对于private的关键字的省略问题——private是类对象的默认访问控制
在这里插入图片描述

(iii)类和结构的区别
在这里插入图片描述

3.实现类成员函数:为类声明中的原型表示的成员函数提供代码

(1)类成员函数定义(就是类方法) 与常规函数的区别
在这里插入图片描述
eg:::叫所属于什么类
在这里插入图片描述
说明如下:
在这里插入图片描述

(2)类方法其他特点:可以访问类的私有成员
在这里插入图片描述

(3)eg
在这里插入图片描述

// stock00.cpp -- implementing the Stock class
// version 00
#include <iostream>
#include "stock00.h"

void Stock::acquire(const std::string & co, long n, double pr)
{
    company = co;
    if (n < 0)
    {
        std::cout << "Number of shares can't be negative; "
                  << company << " shares set to 0.\n";
        shares = 0;
    }
    else
        shares = n;
    share_val = pr;
    set_tot();
}

void Stock::buy(long num, double price)
{
     if (num < 0)
    {
        std::cout << "Number of shares purchased can't be negative. "
             << "Transaction is aborted.\n";
    }
    else
    {
        shares += num;
        share_val = price;
        set_tot();
    }
}

void Stock::sell(long num, double price)
{
    using std::cout;
    if (num < 0)
    {
        cout << "Number of shares sold can't be negative. "
             << "Transaction is aborted.\n";
    }
    else if (num > shares)
    {
        cout << "You can't sell more than you have! "
             << "Transaction is aborted.\n";
    }
    else
    {
        shares -= num;
        share_val = price;
        set_tot();
    }
}

void Stock::update(double price)
{
    share_val = price;
    set_tot();
}

void Stock::show()
{
    std::cout << "Company: " << company
              << "  Shares: " << shares << '\n'
              << "  Share Price: $" << share_val
              << "  Total Worth: $" << total_val << '\n';
}

说明:
(a)成员函数的说明,注意私有成员函数
在这里插入图片描述

(b)内联方法:针对于私有成员函数的
在这里插入图片描述
在这里插入图片描述

(c)如何将类方法应用于对象??
在这里插入图片描述

(d)定义两个类对象的说明,也可以说是定义的两个对象实例化的说明
在这里插入图片描述
在这里插入图片描述

4.使用类

(1)类对象的创建方法有很多,先可以了解下
在这里插入图片描述

(2)eg如下:
在这里插入图片描述

// usestok0.cpp -- the client program
// compile with stock.cpp
#include <iostream>
#include "stock00.h"

int main()
{
    Stock fluffy_the_cat;
    fluffy_the_cat.acquire("NanoSmart", 20, 12.50);
    fluffy_the_cat.show();
    fluffy_the_cat.buy(15, 18.125);
    fluffy_the_cat.show();
    fluffy_the_cat.sell(400, 20.00);
    fluffy_the_cat.show();
    fluffy_the_cat.buy(300000,40.125);
    fluffy_the_cat.show();
    fluffy_the_cat.sell(300000,0.125);
    fluffy_the_cat.show();
    // std::cin.get();
    return 0;
}

在这里插入图片描述

说明:
(1)
在这里插入图片描述

(2)用客户/服务器模型去理解类
在这里插入图片描述

5.修改实现——修改输出的小数点位数

(1)ostream类中包含一些可用于控制格式的成员函数(这两步都得有!!
在这里插入图片描述
上面代码的意思是:给cout对象设置了一个标记,命令cout使用定点表示法
在这里插入图片描述
上面代码的意思是:cout使用定点表示法时,显示三位小数

(2)
在这里插入图片描述
在这里插入图片描述

结果:
在这里插入图片描述

6.小节——重要

(1)指定类设计的第一步是提供类声明

在这里插入图片描述

(2)指定类设计的第二步是实现类成员函数

(a)私有成员函数用内联的方式实现!!
(b)公有成员函数呢?
在这里插入图片描述
在这里插入图片描述

(c)如何操作类对象呢?
在这里插入图片描述

三、类的构造函数和析构函数

(1)C++的目标之一是让使用类对象就像使用标准类型一样。
常规的初始化语法不适用于类型Stock,
在这里插入图片描述
说明:
在这里插入图片描述

(2)so,类对象的初始化方式可以是:
在这里插入图片描述
(3)类构造函数的提出
构造函数:专门用于构造新对象、将值赋给他们的数据成员。

构造函数的要求:

(a)C++为这些成员函数提供了名称和使用语法,而程序员需要提供方法定义;
(b)名称要与类名相同;
(c)构造函数的原型和函数有一个有趣的特征——虽然没有返回值,但没有被声明为void类型 (构造函数没有声明类型)
eg:
在这里插入图片描述

1.声明和定义构造函数

(1)创建Stock的构造函数的过程如下:
构造函数的声明如下:
在这里插入图片描述
构造函数可能的一种定义如下:
注意区别公有成员函数与构造函数的区别:
在这里插入图片描述

(2)不要将类的私有数据成员名作为构造函数的形参名

在这里插入图片描述

2.构造函数初始化对象:2种方式

(1)第一种方式:显示地调用构造函数
在这里插入图片描述
(2)第二种方式:隐式地调用构造函数
在这里插入图片描述

(3)构造函数不能通过对象来调用,而是用来创建构造对象的

在这里插入图片描述
(4)其它
在这里插入图片描述

3.使用默认构造函数:2种方法

(1)第一种方法:没有提供任何构造函数,C++将自动提供默认构造函数
(不懂的话,参考4.使用类那块内容)
在这里插入图片描述
(2)第二种方法:为类定义了构造函数后,就必须为它提供默认构造函数。
(不懂的话,参考5.改进Stock类:重要的eg)
定义默认构造函数的方式有两个:
(a)方法1:
一种是给已有构造函数的所有参数提供默认值
在这里插入图片描述
(b)方法2:
另一种是通过函数重载来定义另一个构造函数——一个没有参数的构造函数
在这里插入图片描述
(c)注意:
在这里插入图片描述

(d)隐式地or显式地使用默认构造函数、隐式地使用构造函数

在这里插入图片描述

4.析构函数

(1)析构函数的定义与作用
在这里插入图片描述
(2)析构函数的特点,以及与构造函数的区别
在这里插入图片描述
(3)什么时候调用析构函数??
在这里插入图片描述

5.改进Stock类:重要的eg

(1)程序说明;
在这里插入图片描述
(2)头文件
在这里插入图片描述

// stock10.h – Stock class declaration with constructors, destructor added
#ifndef STOCK1_H_
#define STOCK1_H_
#include <string>
class Stock
{
private:
    std::string company;
    long shares;
    double share_val;
    double total_val;
    void set_tot() { total_val = shares * share_val; }
public:
    Stock();        // default constructor
    Stock(const std::string & co, long n = 0, double pr = 0.0);
    ~Stock();       // noisy destructor
    void buy(long num, double price);
    void sell(long num, double price);
    void update(double price);
    void show();
};

#endif

(3)实现文件
在这里插入图片描述
在这里插入图片描述

// stock1.cpp – Stock class implementation with constructors, destructor added
#include <iostream>
#include "stock10.h"

// constructors (verbose versions)
Stock::Stock()        // default constructor
{
    std::cout << "Default constructor called\n";
    company = "no name";
    shares = 0;
    share_val = 0.0;
    total_val = 0.0;
}

Stock::Stock(const std::string & co, long n, double pr)
{
    std::cout << "Constructor using " << co << " called\n";
    company = co;

    if (n < 0)
    {
        std::cout << "Number of shares can't be negative; "
                   << company << " shares set to 0.\n";
        shares = 0;
    }
    else
        shares = n;
    share_val = pr;
    set_tot();
}
// class destructor
Stock::~Stock()        // verbose class destructor
{
    std::cout << "Bye, " << company << "!\n";
}

// other methods
void Stock::buy(long num, double price)
{
     if (num < 0)
    {
        std::cout << "Number of shares purchased can't be negative. "
             << "Transaction is aborted.\n";
    }
    else
    {
        shares += num;
        share_val = price;
        set_tot();
    }
}

void Stock::sell(long num, double price)
{
    using std::cout;
    if (num < 0)
    {
        cout << "Number of shares sold can't be negative. "
             << "Transaction is aborted.\n";
    }
    else if (num > shares)
    {
        cout << "You can't sell more than you have! "
             << "Transaction is aborted.\n";
    }
    else
    {
        shares -= num;
        share_val = price;
        set_tot();
    }
}

void Stock::update(double price)
{
    share_val = price;
    set_tot();
}

void Stock::show()
{
    using std::cout;
    using std::ios_base;
    // set format to #.###
    ios_base::fmtflags orig = 
        cout.setf(ios_base::fixed, ios_base::floatfield); 
    std::streamsize prec = cout.precision(3);

    cout << "Company: " << company
        << "  Shares: " << shares << '\n';
    cout << "  Share Price: $" << share_val;
    // set format to #.##
    cout.precision(2);
    cout << "  Total Worth: $" << total_val << '\n';

    // restore original format
    cout.setf(orig, ios_base::floatfield);
    cout.precision(prec);
}

(4)客户文件
在这里插入图片描述
在这里插入图片描述

// usestok1.cpp -- using the Stock class
// compile with stock10.cpp
#include <iostream>
#include "stock10.h"

int main()
{
  {
    using std::cout;
    cout << "Using constructors to create new objects\n";
    Stock stock1("NanoSmart", 12, 20.0);            // syntax 1
    stock1.show();
    Stock stock2 = Stock ("Boffo Objects", 2, 2.0); // syntax 2
    stock2.show();

    cout << "Assigning stock1 to stock2:\n";
    stock2 = stock1;
    cout << "Listing stock1 and stock2:\n";
    stock1.show();
    stock2.show();

    cout << "Using a constructor to reset an object\n";
    stock1 = Stock("Nifty Foods", 10, 50.0);    // temp object
    cout << "Revised stock1:\n";
    stock1.show();
    cout << "Done\n";
  }
	// std::cin.get();
    return 0; 
}

在这里插入图片描述
总结:
(a)注意main()函数中,开头和结尾多了一个大括号
在这里插入图片描述
(b)隐式地声明构造函数显式地声明构造函数
Stock stock1(“NanoSmart”,12,20.0)
等价于<=>
Stock stock1=Stock(“NanoSmart”,12,20.0)
在这里插入图片描述
(c)调用构造函数来创建临时对象,需要注意的是:临时变量啥时候析构(可能有,可能无)
注意:下面的红色箭头表示,在类对象赋值的过程后,对临时对象stock2使用析构的结果
在这里插入图片描述
在这里插入图片描述

有的编译器可能输出的情况如下:
在这里插入图片描述
(d)如果stock1对象已经存在
在这里插入图片描述
(e)局部变量都是放到栈中的
(过程:先是删除stock1 = Stock(“Nifty Foods”, 10, 50.0)的stock1的对象; 然后删除上面的Stock stock2 = Stock (“Boffo Objects”, 2, 2.0)的stock2对象,最后删除Stock stock1(“NanoSmart”, 12, 20.0)的stock1对象,输出的每个对象的内容要根据实际情况去看,很easy)
在这里插入图片描述

(f)给类对象赋值,采用初始化的方式比通过赋值类对象更好!

在这里插入图片描述
(4)C++11列表初始化方式可以用于类:用的少
(a)
在这里插入图片描述
(b)默认构造函数的eg
在main()函数加入如下的代码:
在这里插入图片描述
结果如下的红框:
在这里插入图片描述

(5)const成员函数,写成公有成员函数void stock::show() const的形式(因为没形参),保证函数不会修改调用对象

在这里插入图片描述
在这里插入图片描述

6.构造函数和析构函数小结

(1)构造函数是一种特殊的类成员函数,在创建类对象时被调用。
特点是:

  • [a] 构造函数的名称和类名相同,但是通过函数重载(所以能匹配构造函数与默认构造函数的区别),可以创建多个同名的构造函数,条件是每个函数的特征标(参数列表)都不同。
  • [b]构造函数没有声明类型。通常,构造函数用于初始化类对象的成员,初始化应与构造函数的参数列表匹配。

eg:
在这里插入图片描述
(2) 默认构造函数
在这里插入图片描述
在这里插入图片描述
(3)析构函数
在这里插入图片描述

(4)上面的这些说明最好结合能跑出结果的eg去理解,效果更佳

猜你喜欢

转载自blog.csdn.net/u011436427/article/details/88668120