第十章 对象和类
本章内容包括:
- 定义与实现类
- 使用类
- 对象数组
- 作用域为类的常量
- 作用域内枚举
- 抽象数据类型
类规范由两个部分组成:
- 类声明:以数据成员的方式描述数据部分,以成员函数的方式描述公有接口。
- 类方法定义:描述如何实现成员函数
定义与实现类:
stack00.h
#ifndef D1_STOCK00_H
#define D1_STOCK00_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:
void buy(long num, double price);
void sell(long num, double price);
void update(double price);
void show() const;
const Stock & topval(const Stock &s) const ;
Stock(const std::string &co, long n, double pr); // 构造
Stock();// 构造
~Stock();// 析构
};
#endif //D1_STOCK00_H
stock00.cpp
#include <iostream>
#include "stock00.h"
Stock::Stock(const std::string &co, long n = 0, double pr = 0.0) {
this->_company = co;
if (n < 0) {
std::cout << "Number of shares can‘t be Negative; "
<< _company << " shares set to be 0.\n";
this->_shares = 0;
} else {
this->_shares = n;
}
this->_share_val = pr;
set_tot();
}
Stock::Stock() {
this->_company = "";
this->_shares = 0;
this->_share_val = 0.0;
this-> _total_val = 0.0;
}
Stock::~Stock() {
std::cout << "bye, " << _company << '\n';
}
void Stock::buy(long num, double price) {
if (num < 0) {
std::cout << "Number of num can‘t be Negative; "
<< "Transaction is aborted\n";
} else {
_shares += num;
_share_val = price;
set_tot();
}
}
void Stock::sell(long num, double price) {
if (num < 0) {
std::cout << "Number of num can‘t be Negative; "
<< "Transaction is aborted.\n";
} else if (num > _shares) {
std::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() const{
std::cout << "Company: " << _company
<< " Shares: " << _shares << '\n'
<< " Share Price: $" << _share_val
<< " Total Worth: $" << _total_val << '\n';
}
const Stock & Stock::topval(const Stock &s) const {
if (this->_total_val > s._total_val){
return s;
} else {
return *this;
}
}
定义于类声明中的函数都自动成为内联函数,因此Stock::set_tot()是一个内联函数
使用类:
main.cpp
#include <iostream>
#include "classes/stock00.h"
int main(int argnum, char *args[]) {
Stock fluffy("NanoSmart", 20, 12.50);
fluffy.show();
fluffy.buy(15, 18.25);
fluffy.show();
fluffy.sell(400, 20.00);
fluffy.show();
fluffy.buy(30000, 40.125);
fluffy.show();
fluffy.sell(400000, 12.5);
fluffy.show();
return 0;
}
可以将成员函数定义为 void show() const 来保证成员变量不被修改
对象数组:
#include <iostream>
#include "classes/stock00.h"
int main(int argnum, char *args[]) {
Stock mystuff[4];
mystuff[1].show();
return 0;
}
结果
Company: Shares: 0
Share Price: $0 Total Worth: $0
bye,
bye,
bye,
bye,
作用域为类的常量:
有时,使符号常量的作用域为类很有必要。例如,类声明可能使用字面值30来指定数组的长度,由于该常量对于所有对象来说都是相同的,因此创建一个由所有对象共享的常量是个很不错的主意,但,这样是不行的:
class Bakert{
private:
const int Months = 12;
double const[Months];
};
因为,声明类只是描述了对象的形式,并没有创建对象。因此,创建对象前,将没有用于储存值的空间。有两种方式可以实现这个目标,并且效果相同
-
第一种是在类中声明一个枚举。在类中声明的枚举作用域为整个类,因此可以用枚举为整型常量提供作用域为类的符号名称。
class Bakert{ private: enum {Months=12}; double cons[Months]; };
用这种方式声明枚举并不会创建类数据成员。也就说,所有对象中都不包含枚举。另外,Months只是一个符号名称,编译器用12代替
-
使用关键字static;
class Bakert{ private: static const int Months= 12; double cons[Months]; };
这将创建一个名为Months的常量,该常量与其他静态变量存储在一起,而不是存储在对象中。因此,只有一个Months常量,被所有Bakery对象共享。
作用域内枚举:
传统的枚举可能存在一些问题,其中之一是两个枚举定义中的枚举量可能发生冲突:
enum egg {Small, Medium, Large, Jumbo};
enum t_shirt {Small, Medium, Large, Xlarge};
这这将无法编译。C++11中提供了一种新枚举,其枚举常量的作用域为类:
enum class egg {Small, Medium, Large, Jumbo};
enum class t_shirt {Small, Medium, Large, Xlarge};
egg choice = egg::Large
t_shirt Floyd = t_shirt::Large
c++11 中还提高了作用域内枚举的类型安全。有些情况下,常规枚举将自动转换成为整数,如将其赋值给其他int变量或表达式时。 但是作用域内枚举不能隐式转换
int main(int argnum, char *args[]) {
enum egg_old {Small, Medium, Large, Jumbo};
enum class t_shirt {Small, Medium, Large, Xlarge};
egg_old one = Medium;
t_shirt rolf = t_shirt ::Large;
int king = one;
// int ring = rolf; not allowed
if (king < Jumbo){
std::cout << "Jumbo converted to be int;\n";
}
// if (king < t_shirt::Xlarge) error not allowed
return 0;
}
但必要时,可显式转换
int Frodo = int(t_shirt::Medium);
枚举用某种底层整型表示,C++98中,如何选择取决于实现,因此包含枚举的结构的长度可能随系统而异。对于作用域内枚举,C++11中消除了这种依赖。默认情况下,C++11作用域内枚举的底层类型为int。另外,还提供了一种语法,可用于不同选择
enum class : short pizza {Small, Medium, Large, Xlarge}
抽象数据类型:
栈:stacktp.h
#ifndef D1_STACKTP_H
#define D1_STACKTP_H
template <class Type>
class Stack
{
private:
enum {Max= 10};
Type items[Max];
int _top;
public:
Stack();
explicit Stack(int top);
bool isempty();
bool push(const Type &item);
};
template <class Type>
Stack<Type>::Stack() {
_top = 0;
}
template <class Type>
Stack<Type>::Stack(int top) {
_top = top;
}
template<class Type>
bool Stack<Type>::isempty() {
return false;
}
template<class Type>
bool Stack<Type>::push(const Type &item) {
return false;
}
#endif //D1_STACKTP_H