C++学习之类的简单定义

定义一个类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Stock //class declaration
{
private:
std::string company;
long shares;
double shares_val;
double total_val;
void set_tot() { total_val = shares*shares_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();

};

C++关键字class指出这些代码定义了一个类设计。Stock是这个新类的类型名。该声明能够让我们声明新的Stock类型变量——被称为对象。每个对象都代表一个Stock(股票)

例子:

1
2
Stock A;
Stock B;

我们通过对象声明了新的Stock类型变量,可以代表A、B分别持有的某股票。
接下来,要储存的数据以类数据成员的形式出现(例如company,shares)

例如:
A的ompany存储了公司的名称,shares成员存储了A持有股票的数量,shares_val存储了每股的价格,total_val存储了股票总价格。

要执行的操作以类成员函数的形式出现(又称为方法),例如set_tot()。

访问控制

关键字privatepublic,描述了对类成员的访问控制。使用类对象, 都可以直接访问公用部分,到只能通过公有成员函数来访问对象的私有成员。因此,公有成员函数是程序与对象的私有成员之间的桥梁,提供了对象和程序之间的接口。防止程序直接访问数据,被称为数据隐藏。

  • private:类内可见。
  • public:类内外可见。

类设计尽可能将公有接口和实现细节分开。将实践细节放在一起并将它们与抽象数据类型分开,被称为封装。数据隐藏(数据放在private里)也是封装。将实现的细节放在private里,如set_tot()也是封装。

数据隐藏不仅防止了数据被直接访问,还让用户无需了解数据是如何被表示的。所需要的只是各种类函数的功能,需要接受什么样的参数,返回什么样的结果。原则是将实现的细节从接口设计中分离出来,如果以后对代码进行维护、升级就直接对细节进行修改而无需修改接口。这样对维护程序更有利。

无论类成员是数据成员还是成员函数,都可以在共有部分或者私有部分去声明它。但由于数据隐藏是OOP的主要目标之一,所以数据项通常放在私有部分,组成接口的成员函数放在共有部分。否则无法从程序中调用这些函数。如果把成员函数放在私有部分,则不能直接在程序中调用这种函数,只有公有部分能使用它们。通常这么做是使用私有成员函数来处理不属于公有接口的实现细节部分。

class 和 struct 的区别

类的描述看上去很像是有一个带有privatepublic这样的标签的结构声明。实际上,C++对结构进行了扩展,使之具有与类相同的特效。它们之间的唯一区别是,结构的默认访问类型是public,而类的默认类型是private

C++程序员通常使用类来描述,结构只是用来表示纯粹的数据对象。

tips:如果没有写private就定义成员,那么成员的属性默认是privateprivate是类成员的默认访问控制。

实现类成员函数

定义成员函数时,使用作用域解析运算符::来标识函数所属的类。

1
void Stock::update(double price)

这种表示法意味着我们定义的update是Stock类的成员,不仅表明了update是成员函数,还允许我们把另一个类的成员函数也命名为update。

作用域解析运算符还确定了方法定义的类的身份。所以update()具有类的作用域(class scope),Stock类的其他成员函数不必使用作用域解析运算符就可以使用update()方法,这是因为它们同属一个类,所以update是可见的。

使用类

如果创建两个Stock类

1
2
Stock A;
Stock B;

要使用对象的成员函数,和结构体成员一样,使用成员运算符
1
2
A.show();
B.show();

A调用show()时,shareA.sharesshare_valA.share_val

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
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)
{
if (num < 0)
{
std::cout << "Number of shares sold 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()
{
std::cout << "Company: " << company
<< " Shares: " << shares << '\n'
<< " Share Price: $" << share_val
<< " Total Worth: $" << total_val << '\n';
}

小结

设计一个类的流程

  • 提供类声明。
    ○ 包括数据成员和函数成员
    ○ 声明有私有部分,只能通过成员函数进行访问。公有部分,可以被程序直接访问
    ○ 基本格式如下:
class classname
{
private:
    data member declarations
public:
    member function prototypes
};
○ 公有部分的内容形成了公有接口,因此C++通过类来实现了抽象、数据隐藏、封装的OOP特性
  • 实现类成员函数。
    ○ 可以在类声明里提供完整的函数定义,而不是函数原型。但通常做法是单独提供函数定义,除非函数很小。
    ○ 需要用作用域解析运算符来指明成员函数到底属于哪个类。