C++ Primer Plus的若干收获--(九)

这篇博文我接着上一篇来写,相同讲一些关于类的一些基础知识。

本篇将会继续使用上篇的股票类STock,这里给出接口

ifndef STOCKOO_H_
#define STOCKOO_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(const std::string& co,long n=0,double pr=0.0);
   Stock();
    void acqure(const std::string&co, long n,double ptr);//获得股票
    void buy(long num,double price);//增持
    void sell(long num,double price);//卖出股票
    void update(double price);//更新股票价格
    void show() const;//显示关于所持的股票信息
};
#endif // STOCKOO_H_

9.1 对象数组

实际上。声明对象数组的方法与声明标准类型的数组的方法同样:

Stock mystuff[4];

前面讲过。当程序创建未被现实初始化的对象数组时,总是调用默认构造函数。上述声明要求,这个类要么没有显式的定义不论什么构造函数(这样的情况下,将使用不运行不论什么操作的隐式默认构造函数),要么定义了一个显式的默认构造函数。每一个元素都是一个Stock对象。

我们也能够利用多种构造函数来初始化我的对象数组

const int STK=10;
Stock stocks[STK]={
   Stock("NAnoSmart",12.5,20),
   Stock(),
   Stock("Monolithis",130,2.5),
};

9.2 类作用域

在类定义的名称的作用于都为整个类,作用域为整个类的名称仅仅在该类中是已知的,在类外是不可知的。因此。能够在不同类中使用同样的类成员名而不会引起冲突。

比方。Stock类的shares成员不同于JobRide的shares成员。

另外。类的作用域意味着不能从外部直接訪问类的成员,共同拥有成员函数也是如此。也就是说,要调用公有成员函数。必须通过对象。

总之,在类声明或成员函数定义中。能够使用维修时的成员名称。构造函数在被调用时,才干被识别,由于它的名称与类名同样。在其它情况下,使用类成员名时,必须依据上下文使用直接成员运算符(.),间接成员运算符(->)。或者是作用域解析符(::)。

有时候。使用符号常量的作用域为类含实用。

假设我写下例如以下代码,您可能觉得这样做是可行的

class Bakery
{
private:
  const int Months=12;
  double costs[Months];
  ...
}

可是这是行不通的,由于声明类仅仅是描写叙述了对象的形态,并没有创建对象。

因此在创建对象前。将没有存储值的空间。

然而,有两种方式能够实现这个目标,而且效果同样。第一种是在类声明中声明一个枚举。在类声明中声明的枚举作用域为整个类,因此能够用枚举为整形常量提供作用域为整个类的符号名称。则上述代码能够这样写

class Bakery
{
private:
  enum{Months=12};
  double costs[Months];
  ...
}//这样的声明方式的枚举并不会创建类数据成员。也就是说全部对象都不会包括枚举。<strong>Month仅仅是一个符号名称。

</strong>

还有一种方式是使用keyword——static

class Bakery
{
private:
  static const int Months=12;
  double costs[Months];
  ...
}

这个样将创建一个名为MOnth的常量,该常量将其与其它的静态变量存储在一起,而不是存储在对象中。

9.3 抽象数据类型

Stock类很详细。然而,程序猿经常通过定义类来表示更通用的概念。比如,就实现计算机专家所说的抽象数据类型(ADT)。顾名思义。ADT以通用的方式描写叙述数据类型,而没有引入语言或是实现细节。这里简要的给出栈的接口

ifndef STACK_H_
#define STATC_H_
typedef unsigned liong Item;

class Stack
{
private:
    enum{Max=10};
    Item items[10];
    int top;
public:
    Stack();
    bool isempty() const;
    bool isfull();
    bool push(const Item &item);
    bool pop(Item& item);
};

#endif // STACK_H_

接下来将会进入到类的使用部分

9.4 运算符重载

运算符重载是一种形式的C++多态。

在这之前我们介绍过函数的重载或称为函数的多态。旨在让您可以使用同名的函数来完毕同样的基本操作。

运算符重载将重载的概念扩展到运算符上,匀速赋予C++运算符多种含义。要重载运算符,需使用被称为运算符函数的特殊函数形式。其格式例如以下:

<span style="font-size:18px;">operatorop(argument-list)</span>

比如,operator+()重载+运算符,operate*()重载*运算符。

op必须是一个有效的C++运算符,不能虚构一个新的运算符。不能重载@这个符号。

以下我们来看一个运算符重载的演示样例:计算时间

ifndef MYTH0_H_
#definr MYTH0_H_

class Time
{
private:
    int hours;
    int minutes;
public:
    Time();
    Time(int h,int m=0);
    void AddMin(int m);
    void AddHr(int h);
    void Reset(int h=0,int m=0);
    Time Sum(const Time & t)const;
    void show() const;
};
#endif // MYTH0_H_

这里给出mytime0.cpp

include<iostream>
#include"mytime0.h"

Time::Time()
{
    hours=minutes=0;
}

Time::Time(int h,int m)
{
    hours=h;
    minutes=m;
}

void Time::AddMin(int m)
{
    minutes+=m;
    hours+=minutes/60;
    minutes%=60;
}

void Time::AddHr(int h)
{
    hours+=h;
}

void Time::Reset(int h,int m)
{
    hours=h;
    minutes=m;
}

Time Time::Sum(const Time& t)const
{
    Time sum;
    sum.minutes+t.minutes;
    sum.hours=hours+t.hours+sum.minutes/60;
    sum.minutes%=60;
    return sum;
}

void Time::Show() const
{
    std::cout<<hours<<"hours,"<<minutes<<"minutes";
}

这个类比較基础,我就简单的说一下当中的一个函数Sum()。

注意參数是引用,但返回的却不是引用。将參数声明为引用的目的是为了提高效率。假设按值传递Time对象,功能同样,可是效率明显不如引用。

可是返回值不能是引用。因为sum是一个局部变量,当函数调用结束时,这个变量将不再存在。因此引用将指向一个不存在的变量。使用返回类型Time意味着程序将在删除sum之前构造它的拷贝。调用该函数将得到它的拷贝。

9.5 加入重载运算符

以下我们来给上面的函数加入重载函数。用operate+()来替换上述的sum()函数

Time Time::operator+(const Time& t)const
{
    Time sum;
    sum.minutes=sum.minutes+t.minutes;
    sum.hours=hours+t.hours+sum.minutes/60;
    sum.minutes%=60;
    return sum;
}

这样我们就能够这样调用operator+()方法

total=coding.operator+(fixing);

total=coding+fixing;//二者等价

这两种方法都将调用operator方法。

注意,在运算符表示法中,运算符左側的对象时调用对象。运算符右側的对象是作为參数被传递的对象。

因此这种代码也是能够的

Time t1,t2,t3,t4;
t4=t1+t2+t3;//valid</span>

9.6 重载的限制

多数C++运算符都能够这种方式重载。

重载的运算符不必是成员函数,但必须至少是有一个操作数是用户定义的类型。以下具体介绍其限制:

(1)重载后的运算符必须至少有一个操作数使用户定义的类型,这将防止用户为标准类型重载运算符。比方。不能将-运算符用来计算两个数的和。

(2)使用运算符时不能违反运算符原来的句法规则,比方,不饿能将%重载成一个操作数。也不能改动其优先级。

(3)不能创建新的运算符,如@。

(4)不能重载以下的运算符

  • sizeof:sizeof运算符;
  • . :成员运算符;
  • :::作用域解析运算符;
  • ?::条件运算符;
  • const_cast:强制类型转换运算符;
  • dynamic_cast:强制类型转换运算符;
  • static_cast:强制类型转换运算符;

(5)多数运算符都能够通过成员或非成员函数进行重载,可是以下的运算符仅仅能通过成员函数进行重载。

  • =:赋值运算符;
  • ():函数调用运算符;
  • 【】下标运算符。
  • ->:通过指针訪问成员运算符

好了,这次就到这里吧。

好累啊,手都酸了。

时间: 2024-11-10 11:55:57

C++ Primer Plus的若干收获--(九)的相关文章

C++ Primer Plus的若干收获--(八)

接下我会比较系统的介绍OOP的核心--类这个概念.可能会写的比较繁琐,比较多,但是自己理解总是好的.还记得上学期刚开始的时候老师讲的数据结构,一上来就来个LIst的一个大类,结果全班就傻了,完全不知所云(ps:博主是数学系,只学过C),然后自己就坐在图书馆借了两大本C++书开始啃了起来,大概啃了两个月才把C++学了个大概,尤其是读到类这块都是三四百行的常常的代码,看的那叫一个痛苦啊.不过自此之后就真正喜欢上这门语言了,再到之后能用C++写上个一两千行的代码,才发现之前的努力还是有收获的.好了,废

C++ Primer Plus的若干收获--(十)

明天就要回学校了,本来回家之前是有一片宏图伟志的,无奈只能抱着这可怜的十篇博客回学校了.自己马上就要大三,大学的下一半马上就要开始了,我的未来还有什么在等待着我呢,好期待!!! 10.1 友元 我们知道C++控制对类对象私有部分的访问.通常,公有类方法是唯一的途径,但是除此之外C++还提供了另外一种机制:友元.友元有三种友元函数,友元类与友元成员函数.在介绍如何成为友元前,先介绍一下为何需要友元.在为类重载二元运算符是常常需要友元.将之前的Time对象乘以实数就是这种情况. 我们之前重载了+ T

C++ Primer Plus的若干收获--(七)

这篇博文主要讲了名称空间,说实话在接触之前一直对这方面很感兴趣,现在来好好的学习一番. 7.1 新的名称空间特性 C++新增了这样一种功能,即通过定义一种新的声明区域来创建命名的名称空间,这样做的目的之一是提供一个声明名称的区域.一个名称空间的名称不会与另外一个空间的名称发生冲突,同时允许程序的其他部分使用该名称中声明的东西.比如,下面的代码使用关键字namespace创建了名称空间: namespace Jack { double pail; void fetch(); int pal; st

C++ Primer Plus的若干收获--(二)

哎,真是不想吐槽考驾照的艰辛历程了.跑到大西郊,顶着大太阳,一天就能摸上个十几分钟二十分钟的车,简直不要太坑爹,这两天真是做的我屁股疼的不行. .. 今天果断不去了.仅仅可惜我的大阿根廷啊,坚持到最后功亏一篑惜败于德国,枉我四点自然醒起来看了接下来的比赛. 不能不佩服诺伊尔,拉姆.博阿滕组成的后防线,让阿根廷整场没有几个有威胁的射门.祝贺我大克洛泽在职业生涯暮年能将大力神杯捧入怀中... 拜拜   巴西世界杯,拜拜  阿根廷,拜拜,    梅西. 2.1  字符串常量 将字符数组初始化为字符串的

学习C++ Primer 的个人理解(九)

这一章介绍顺序容器,在之前的第三章中,了解到的vector就属于顺序容器的一种. 一个容器就是一些特定类型对象的集合. 除了vector,还有哪些顺序容器? vector: 大小可变,随机访问的速度很快,但是在尾部之外的部分插入或删除元素可能会很慢. deque : 随机访问的速度很快,在头和尾插入或删除的速度都很快. list: 双向链表,只支持双向顺序访问,在任何位置插入或删除操作都很快(链表的特性) forward_list: 单向链表,只支持单向的随机访问.在任何位置插入或删除都很快 a

【C++ Primer每日一刷之九】创建动态数组

表达式 C++ 提供了丰富的操作符,并定义操作数为内置类型时,这些操作符的含义.除此之外,C++ 还支持操作符重载,允许程序员自定义用于类类型时操作符的含义.标准库正是使用这种功能定义用于库类型的操作符. 本章重点介绍 C++ 语言定义的操作符,它们使用内置类型的操作数:本章还会介绍一些标准库定义的操作符.第十四章将学习如何定义自己的重载操作符. 表达式由一个或多个操作数通过操作符组合而成.最简单的表达式仅包含一个字面值常量或变量.较复杂的表达式则由操作符以及一个或多个操作数构成. 每个表达式都

c++primer第五版第十九章练习

19.1 #include <iostream> #include <cstdlib> void *operator new(std::size_t n){ std::cout << "new(size_t)\n"; if (void *mem = malloc(n)) return mem; else throw std::bad_alloc(); } void operator delete(void *mem) noexcept{ std::c

C++ Primer 学习笔记_54_STL剖析(九):迭代器适配器{(插入迭代器back_insert_iterator)、IO流迭代器(istream_iterator、ostream_i

回顾 适配器 1.三种类型的适配器: (1)容器适配器:用来扩展7种基本容器,利用基本容器扩展形成了栈.队列和优先级队列 (2)迭代器适配器:(反向迭代器.插入迭代器.IO流迭代器) (3)函数适配器:函数适配器能够将仿函数和另一个仿函数(或某个值.或某个一般函数)结合起来. [1]针对成员函数的函数适配器 [2]针对一般函数的函数适配器 一.迭代器适配器 1.反向迭代器 2.插入迭代器 3.IO流迭代器 其中反向迭代器,利用正向迭代器实现可以参考以前<46_STL剖析(三)>. 二.插入迭代

C#学习(九)- WP8.1开发的一些收获

本篇属于总结性记录,知识点会相对凌乱. 1. 关于SQLlite数据库的应用 关于如何设置Visual Studio 2013使SQLlite数据库可用,参见http://www.cnblogs.com/tiny-home/p/4474861.html,在此不再赘述.主要分享我使用SQLlite过程中遇到的问题和收获. 首先要建一个类,用以表示在SQLlite数据库中表示的记录,相当于普通数据库中的create语句,用来定义表中每条记录有多少列,每列是什么类型的量,每条记录就是一个对象.比如: