2020 我的C++的学习之路 第十章 对象和类

以C++ Primer Plus为参考书籍,自身归纳知识点,加深记忆。

过程性编程与面向对象编程

过程性编程:首先考虑要遵循的步骤,然后考虑如何表示这些数据
面向对象编程:首先从用户的角度考虑对象,描述对象所需的数据以及描述用户与数据交互所需的操作,完成对接口的描述后,需要确定如何实现接口与数据储存,最后使用新的设计方案创建出程序。

对象和类

类是一种将抽象转化为用户定义类型的C++工具,将数据表示和数据操作的方法组合成一个整合包。
一般来说,类规范由两个部分组成:
①类声明:以数据成员的方式描述数据部分,以成员函数(方法)的方式描述公有接口
②类方法定义:描述如何实现类成员函数
简单地说,类声明提供蓝图,类方法定义提供细节。

类声明

//类声明
//stock00.h
#include<iostream>

class Stock//class不同于模板参数的typename,不能代替,Stock为新类型名
{
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(); 
};

使用类对象的程序都可以使用公有部分,但只能通过公有成员函数访问对象的私有成员。将实现细节放在一起并将它们与抽象分开被称为封装。

实现类成员函数

成员函数的定义与常规函数定义非常相似,它们有函数头和函数体,也可以有返回类型和参数,但还有两个特殊的特征:
①定义成员函数,使用作用域解析符::来表示函数所属的类
②类方法可以访问类的private组件

void Stock::update(double price)//update是Stock类的成员函数,还可以将另一个类的成员函数声明为update
//标识符update()具有类作用域
// 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';
}

方法与对象

创建对象:

Stock kate,joe;

使用成员函数:

kate.show();
joe.show();

创建的每一个对象都有自己的存储空间,用于存储其内部的变量和类成员,但同一个类的所有对象共享同一组类的方法,即每种方法只有一个副本,在OOP中,调用成员函数被称为发送消息,因此将同样的消息发送给两个不同的对象将调用同一个方法,但该方法被用于两个不同的对象

// 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;
}

类的构造函数与析构函数

声明和定义构造函数

Stock (const string &co,long n =0, double pr = 0.0);//没有返回类型,构造函数声明
//定义构造函数
Stock::Stock(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();
}

使用构造函数

构造函数初始化对象有两种方式:

Stock food = Stock("World Cabbage",250,2.5);//显示调用构造函数
Stock garmer("Furry Mason",50,1.25);//隐式调用构造函数
Stock *pstock = new Stock("Electroshock Games",18,20.5);//对象指针

无法使用对象调用构造函数,因为在构造函数构造出对象之前,对象是不存在的,因此构造函数创建对象但不能通过对象调用

默认构造函数(defult constructor)

默认构造函数实在未提供显示初始值时,用来创建对象的构造函数。如果没有提供任何构造函数,C++将自动提供默认构造函数,它是默认构造函数的隐式版本,不做任何工作。默认构造函数没有参数,因为没有声明中不包含值

定义默认构造函数的方式有两种:

Stock(const string &co="ERROR",int n=0,double pr=0);//给已有构造函数的所有参数提供默认值
Stock();//函数重载,一个没有任何参数的构造函数。
//只有能有一种默认构造函数,不要同时采用

析构函数(destructor)

用构造函数创建一个对象后,程序负责跟踪该对象,直到其过期为止。对象过期时,程序将自动调用一个特殊的成员函数完成清理工作。
和构造函数一样,析构函数的名称很特殊。在类名前加上~,没有返回值和声明类型,并且没有参数:

~Stock();

①如果创建的是静态存储类对象,析构函数将在程序结束时自动调用
②如果创建的是自动存储类对象,析构函数将在程序运行完代码块时自动被调用
③如果对象是通过new创建,析构函数将驻留在栈内存或者自由存储区中,当使用delete释放内存时,析构函数将会自动被调用
④程序创建临时对象来完成特定操作,在这种情况下,程序将结束该对象的使用时自动调用其析构函数。

// 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
// 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);
}
// 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; 
}

const成员函数

void show()const;//将const放在函数括号后面

C++11列表初始化

Stock hot = {"Dedwadd dfwf fw",110,23.2};
Stock dw {"sdded dad",121,2.1};//与构造函数匹配
Stock temp {};//与默认构造函数匹配

this指针

this指针指向用来调用成员函数的对象。

stock1.topval(stock2)//this设置为stock1的地址

每个成员函数包括构造函数和析构函数都有一个this指针,this指针指向调用对象,在函数括号后面使用const限定符将this限定为const,这样不能使用this修改对象的值。

对象数组

声明对象数组的方法与声明标准类型数组相同

Stock mystuff[4];

可以用构造函数来初始化数组元素,在这个情况下必须为每个元素调用构造函数:

Stock stocks[4] = {
	Stock("dqguydi dfwq",12.5,20),//也可以交叉使用默认构造函数
	Stock("dswd",12.2,21),
	Stock("dedes ded"12.6,78),
	Stock("dsve fgte"32.9,89)
	};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值