首页 > 编程语言 >C++primer 第十章对象和类学习笔记

C++primer 第十章对象和类学习笔记

时间:2024-09-11 22:50:41浏览次数:3  
标签:const val int double void 第十章 C++ primer Stock

OPP特性:

抽象

封装和数据隐藏

多态

继承

代码的可重用性

过程性和面向对象的编程

从用户的角度考虑对象

抽象和类

基本类型完成的工作:

  • 决定数据对象需要的内存单元
  • 决定如何解释内存中的位
  • 决定可使用数据对象执行的操作或方法

 c++ 中的类

类规范

  • 类声明:以数据成员的方式描述数据部分,以成员函数(方法)的方式描述公有接口。
  • 类方法定义:描述如何实现类成员的函数
#include <iostream>
#include <cstring>

class Stock // class declaration
{
    private:
        char company[30];
        int shares;
        double share_val;
        double total_val;
        void set_tot() {total_val = shares * share_val;}
    public:
        void acquire(const char * co, int n, double per);
        void buy (int num, double price);
        void sell (int num, double price);
        void update(double price);
        void show();
}; // semicolon

类内部包括成员和方法

只能通过公有函数来访问对象的私有成员。例如要修改Stock类的shares成员只能通过Stock的成员函数。

创建类成员函数

成员函数包括函数头和函数体,返回类型和参数,和两个特殊特征:

  • 定义成员函数时,使用作用域解析操作符(::)来标识函数所属的类。
  • 类方法可以访问类的private组件

 update是Stock类的成员,同时可以定义另外一个类的成员函数。例如

void Buffoon::update()

方法可以访问类的私有成员。可以在show()中使用

cout << "Company: " << company << endl;

其中company是Stock类的私有成员。

void Stock::acquire(const char *co, int n, double pr)
{
    std::strncpy(company, co, 29);
    company[29] = '\0';
    if (n < 0)
    {
        std::cerr << "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(int num, double price)
{
    if (num < 0)
    {
        std::cerr << "Number of shares purchased can't be negative"
                  << "Transaction is aborted.\n";
    }
    else
    {
        shares += num;
        share_val = price;
        set_tot();
    }
}

void Stock::sell(int num, double price)
{
    using std::cerr;
    if (num < 0)
    {
        cerr << "Number of shares sold can't be negative."
             << "Transaction is aborted.\n";
    }
    else if (num > shares)
    {
        cerr << "Yon 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::endl;

    cout << "Company: " << company
         << "Shares: " << shares << endl
         << "Share Price: $" << share_val
         << "Total worth: $" << total_val << endl;
}

成员函数说明

acquire() 表示首次购买, buy 和sell表示购买和出售

cerr用于错误信息

内联方式

内联函数要求在每个使用他的文件中都要对其进行定义。

方法使用哪个对象

调用成员函数式,他将使用调用他的对象的数据成员

例如kate.show(), 相当于把show内部的shares 解释为 kate.shares

使用类

下面是完整代码

#include <iostream>
#include <cstring>

class Stock // class declaration
{
private:
    char company[30]; // 成员
    int shares;
    double share_val;
    double total_val;
    void set_tot() { total_val = shares * share_val; }

public:
    void acquire(const char *co, int n, double per); // 方法
    void buy(int num, double price);
    void sell(int num, double price);
    void update(double price);
    void show();
}; // semicolon
void Stock::acquire(const char *co, int n, double pr)
{
    std::strncpy(company, co, 29);
    company[29] = '\0';
    if (n < 0)
    {
        std::cerr << "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(int num, double price)
{
    if (num < 0)
    {
        std::cerr << "Number of shares purchased can't be negative"
                  << "Transaction is aborted.\n";
    }
    else
    {
        shares += num;
        share_val = price;
        set_tot();
    }
}

void Stock::sell(int num, double price)
{
    using std::cerr;
    if (num < 0)
    {
        cerr << "Number of shares sold can't be negative."
             << "Transaction is aborted.\n";
    }
    else if (num > shares)
    {
        cerr << "Yon 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::endl;

    cout << "Company: " << company
         << "  Shares: " << shares << endl
         << "  Share Price: $" << share_val
         << "  Total worth: $" << total_val << endl;
}

int main()
{
    using std::cout;
    using std::ios_base;
    Stock stock1;
    stock1.acquire("NanoSmart", 20, 12.50);
    cout.setf(ios_base::fixed);
    cout.precision(2);
    cout.setf(ios_base::showpoint);
    stock1.show();
    stock1.buy(15, 18.25);
    stock1.show();
    stock1.sell(400, 20.00);
    stock1.show();
    return 0;
}

类的构造函数和析构函数

C++的目标之一是使用类对象就像使用标准类型一样。例如想int一样初始化对象。如下

int year = 2001;   // valid initialization
struct thing 
{
   char * pn;
   int m;
}

thing amabob = { "wodget", -23} //valid initialization
Stock hot = {"Sukie's Autos, Inv.", 200, 50.2}  // compile error

不能初始化Stock对象是因为,数据部分的访问转态是私有的。只能通过成员函数来访问数据成员。

类构造函数:专门用于构造新对象。

构造函数没有声明类型。

声明和定义构造函数

采用默认参数来完成。如下是函数原型

Stock(const char *co, int n = 0, double pr = 0.0);

下面是一种可能的定义

Stock::Stock(const char * co, int n, double pr)
{
    std::strncpy(company, co, 29);
    company[29] = '\0';
    

    if (n < 0)
    {
         std::err << "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, 1.25);

隐式调用

Stock garment ("Furry Mason", 50, 2.5);

构造函数和new一起使用的方法

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

Stock对象没有名称,属于对象指针。

无法使用对象来调用构造函数。

默认构造函数

例如上面的完整代码中的

Stock stock1;

等价于 int x;

只有在没有定义任何构造函数的时候,才能编译。否则会报错。

析构函数

析构函数完成清理工作。

析构函数在类名前加~;

~Stock();

析构函数不执行任何操作的函数;

改进Stock类

C++的通常做法,将程序组织成独立的文件。

我们将类声明放在stock1.h中

类方法被放在stock1.cpp中

头文件stock1.h
#ifndef STOCK1_H_
#define STOCK1_H_

class Stock // class declaration
{
private:
    char company[30]; // 成员
    int shares;
    double share_val;
    double total_val;
    void set_tot() { total_val = shares * share_val; }

public:
    Stock();
    Stock(const char *co, int n = 0, double pr = 0.0);
    ~Stock();
    void buy(int num, double price);
    void sell(int num, double price);
    void update(double price);
    void show();
};
#endif
方法文件stock1.cpp
#include <iostream>
#include <cstring>
#include "stock1.h"

Stock::Stock()
{
    std::cout << "Default constructor called\n";
    std::strcpy(company, "no name");
    shares = 0;
    share_val = 0.0;
    total_val = 0.0;
}
Stock::Stock(const char *co, int n, double pr)
{
    std::cout << "Constructor using " << co << " called\n";
    std::strncpy(company, co, 29);
    company[29] = '\0';

    if (n < 0)
    {
        std::cerr << "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()
{
    std::cout << "Bye, " << company << "!\n";
}
// other methods
void Stock::buy(int num, double price)
{
    if (num < 0)
    {
        std::cerr << "Number of shares purchased can't be negative"
                  << "Transaction is aborted.\n";
    }
    else
    {
        shares += num;
        share_val = price;
        set_tot();
    }
}

void Stock::sell(int num, double price)
{
    using std::cerr;
    if (num < 0)
    {
        cerr << "Number of shares sold can't be negative."
             << "Transaction is aborted.\n";
    }
    else if (num > shares)
    {
        cerr << "Yon 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::endl;

    cout << "Company: " << company
         << "  Shares: " << shares << endl
         << "  Share Price: $" << share_val
         << "  Total worth: $" << total_val << endl;
}
使用类文件
#include <iostream>
#include "stock1.h"
int main()
{
    using std::cout;
    using std::ios_base;
    cout.precision(2);
    cout.setf(ios_base::fixed, ios_base::floatfield);
    cout.setf(ios_base::showpoint);

    cout << "Using constructors to create new objects\n";
    Stock stock1("NanoSmart", 12, 20.0);
    stock1.show();
    Stock stock2 = Stock("Boffo Objects", 2, 2.0);
    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);
    cout << "Revised stock1: \n";
    stock1.show();
    cout << "Done\n";
    return 0;
}
 const成员函数

只要类方法没有修改调用对象,后面都应加上const,例如

void show() const;

this 指针

比较两个类对象的值,返回其中较大的一个。

const Stock & topval (const Stock & s ) const;

两个const分别表示两个调用对象的值不变

函数调用如下

top = stock1.topval(stock2);

const Stock & Stock::topval (const Stock & s) const
{
    if (s.total_val > total_val)
      return s;
    else 
      return ???;
}

第二种情况的返回值没有称呼。

解决方法: this指针。

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

const Stock & Stock::topval (const Stock & s) const
{
    if (s.total_val > total_val)
      return s;
    else 
      return *this;
}
 头文件stock2.h
#ifndef STOCK2_H_
#define STOCK2_H_

class Stock // class declaration
{
private:
    char company[30]; // 成员
    int shares;
    double share_val;
    double total_val;
    void set_tot() { total_val = shares * share_val; }

public:
    Stock();
    Stock(const char *co, int n = 0, double pr = 0.0);
    ~Stock(){};
    void buy(int num, double price);
    void sell(int num, double price);
    void update(double price);
    void show() const;
    const Stock & topval (const Stock & s) const;
};
#endif
 类方法stock2.cpp
#include <iostream>
#include <cstring>
#include "stock2.h"

Stock::Stock()
{
    std::cout << "Default constructor called\n";
    std::strcpy(company, "no name");
    shares = 0;
    share_val = 0.0;
    total_val = 0.0;
}
Stock::Stock(const char *co, int n, double pr)
{
    std::cout << "Constructor using " << co << " called\n";
    std::strncpy(company, co, 29);
    company[29] = '\0';

    if (n < 0)
    {
        std::cerr << "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()
//{
//   std::cout << "Bye, " << company << "!\n";
//}
// other methods
void Stock::buy(int num, double price)
{
    if (num < 0)
    {
        std::cerr << "Number of shares purchased can't be negative"
                  << "Transaction is aborted.\n";
    }
    else
    {
        shares += num;
        share_val = price;
        set_tot();
    }
}

void Stock::sell(int num, double price)
{
    using std::cerr;
    if (num < 0)
    {
        cerr << "Number of shares sold can't be negative."
             << "Transaction is aborted.\n";
    }
    else if (num > shares)
    {
        cerr << "Yon 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() const
{
    using std::cout;
    using std::endl;

    cout << "Company: " << company
         << "  Shares: " << shares << endl
         << "  Share Price: $" << share_val
         << "  Total worth: $" << total_val << endl;
}

const Stock &Stock::topval(const Stock &s) const
{
    if (s.total_val > total_val)
        return s;
    else
        return *this;
}

 对象数组

声明对象数组的方法和声明标准类型数组相同,例如

Stock mystuff [4] 

初始化对象数组,这个类一定要有默认构造函数

使用类函数

#include <iostream>
#include "stock2.h"

const int STKS = 4;
int main()
{
    using std::cout;
    using std::ios_base;

    Stock stocks[STKS] =
        {
            Stock("NanoSmart", 12, 20.0),
            Stock("Boffo Objects", 200, 2.0),
            Stock("Monolithic Obelisks", 130, 3.25),
            Stock("Fleep Enterprises", 60, 6.5)};

    cout.precision(2);
    cout.setf(ios_base::fixed, ios_base::floatfield);
    cout.setf(ios_base::showpoint);

    cout << "Stock holdings: \n";
    int st;
    for (st = 0; st < STKS; st++)
        stocks[st].show();

    Stock top = stocks[0];
    for (st = 1; st < STKS; st++)
        top = top.topval(stocks[st]);
    cout << "\nMost valuable holding: \n";
    top.show();

    return 0;
}

接口和实现小结

类作用域

类成员只在所属中是已知的,所以不同的类可以有相同的名称。并且不能从外部访问

类的声明中不能存储对象

但是可以用关键词static

static const int Len = 30;

抽象数据类型

头文件stack.h

#ifndef STACK_H_
#define STACK_H_

typedef unsigned long Item;

class Stack
{
private:
    enum
    {
        MAX = 10
    };
    Item items[MAX];
    int top;

public:
    Stack();
    bool isempty() const;
    bool isfull() const;

    bool push(const Item &item);

    bool pop(Item &item);
};
#endif

类方法文件 stack.cpp

#include <iostream>
#include "stack.h"
Stack::Stack()
{
    top = 0;
}

bool Stack::isempty() const
{
    return top == 0;
}

bool Stack::isfull() const
{
    return top == MAX;
}

bool Stack::push(const Item &item)
{
    if (top < MAX)
    {
        items[top++] = item;
        return true;
    }
    else
        return false;
}

bool Stack::pop(Item &item)
{
    if (top > 0)
    {
        item = items[--top];
        return true;
    }
    else
        return false;
}

使用类文件

#include <iostream>
#include <cctype>
#include "stack.h"
int main()
{
    using namespace std;
    Stack st;
    char ch;
    unsigned long po;
    cout << "Please enter A to add a purchase order, \n"
         << "P to process a PO, or Q to quit.\n";
    while (cin >> ch && toupper(ch) != 'Q')
    {
        while (cin.get() != '\n')
            continue;
        if (!isalpha(ch))
        {
            cout << '\a';
            continue;
        }
        switch (ch)
        {
        case 'A':
        case 'a':
            cout << "Enter a PO number to add: ";
            cin >> po;
            if (st.isfull())
                cout << "stack already full\n";
            else
                st.push(po);
            break;
        case 'P':
        case 'p':
            if (st.isempty())
                cout << "stack already empty\n";
            else
            {
                st.pop(po);
                cout << "PO #" << po << " popped\n";
            }
            break;
        }
        cout << "Please enter A to add a purchase order, \n"
             << "P to process a PO, or Q to quit. \n";
    }
    cout << "Bye\n";
    return 0;
}

标签:const,val,int,double,void,第十章,C++,primer,Stock
From: https://blog.csdn.net/weixin_48442204/article/details/141948247

相关文章

  • 【C++】new的底层实现原理
    文章目录理解C++`new`的原理1.`new`的基本工作流程2.`new`和`malloc`的区别3.`new`的底层实现4.`new[]`与`delete`的配对使用5.自定义`new`和`delete`6.定位new7.内存泄漏与异常安全理解C++new的原理在C++中,new操作符用于在堆上动态分......
  • 【C++】C++ 多态的底层实现原理
    文章目录1.多态的定义与作用2.虚函数与虚函数表(vtable)3.虚函数表(vtable)4.虚函数调用的底层过程5.内存布局中的虚函数指针6.多重继承中的虚函数表7.RTTI与动态类型识别1.多态的定义与作用多态指的是同一操作在不同对象上具有不同的表现。C++中多态分为两......
  • 递归(c++)
    递归1、斐波那契额数列基础代码#include<iostream>usingnamespacestd;intf(intn){ if(n==1)return1; if(n==2)return2; returnf(n-1)+f(n-2);}intmain(){ intn; cin>>n; cout<<f(n)<<endl; return0;}递归实现指数......
  • c++ 数字转化成 string
       ULONG转换成string方法1:使用std::to_string(C++11及更高版本)std::to_string是将数字转换为字符串的简单方式,适用于C++11及更高版本。#include<iostream>#include<string>intmain(){ULONGvalue=1234567890UL;//定义一个ULONG类型的值/......
  • c++ string 转换成 guid
      在C++中,将一个字符串转换为GUID(GloballyUniqueIdentifier)可以通过以下方法实现。GUID通常是128位(16字节)的标识符,以标准格式表示,例如:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx。在C++中,常用的库之一是WindowsAPI,它提供了处理GUID的相关功能。这里是一个示例代码,将字符串转换......
  • 【自用22.】C++类的静态数据成员以及静态成员函数
    需要获取总的人数,如何实现?方案一:使用全局变量,在构造函数中对这个全局变量进行修改具体代码如下:在Human.cpp中定义全局变量,并在构造函数中对人数进行增加操作#include"Human.h"#include<iostream>usingnamespacestd;intHumanCount=0;Human::Human(){ name......
  • C++复习day10
    智能指针为什么需要智能指针?#include<iostream>usingnamespacestd;intdiv(){ inta,b; cin>>a>>b; if(b==0) throwinvalid_argument("除0错误"); returna/b;}voidFunc(){ //1、如果p1这里new抛异常会如何? //2、如果p2这里new抛异常会......
  • C++ web框架:matt-42/lithium
    一、代码示例#include<lithium_http_server.hh>#include<lithium_pgsql.hh>#include"symbols.hh"usingnamespaceli;intmain(){//创建PostgreSQL数据库连接pgsql_databasedb=pgsql_database(s::host="localhost"......
  • C++中的数组,字符串数组,pair数组
    1.C++中的字符串数组: 2.C++中的常量数组 这个constpair<int,string>valueSymbols[]定义了一个常量数组,数组中的每个元素都是一个pair<int,string>类型的对象。pair是C++标准模板库(STL)中的一个模板类,用于将两个值组合成一个单一的对象。在这个特定的例子中,pair的第一个......
  • C++入门教程:第八篇 - 文件I/O操作
    C++入门教程:第八篇-文件I/O操作文件I/O(输入/输出)是程序与外部存储设备进行数据交换的关键操作。在C++中,文件I/O操作由标准库提供的流类完成。通过这些流类,程序可以读写文件,处理文件内容。本文将介绍C++中的文件I/O基础,包括如何打开、读写和关闭文件。1.文件流基础C++提......