一、接口
1.
举个例子,A想要去B的家里做客,当然,A不能直接穿墙或瞬移进入到B家里去访问,他必须通过某种方式或渠道才能进入到B的家里。这时候,这种方式或渠道可以称之为B的家对外的接口。
2.接口可以分为两种:公共接口(Public) 和 私有接口(private) 。公共接口可以看做是B家的窗户、大门,任何人都可以访问;私有接口则可以看做B家里的私密通道,只有他家里的成员对象或者通过他家里的私密方法才能进入和访问。
请看如下代码:
#ifndef Stock_hpp
#define Stock_hpp
#include <iostream>
#include <stdio.h>
#include <string.h>
/*
*class关键字指出这些代码定义了一个类设计
*Stock是这个类的类型名(类的名称)
*通过这个声明,我们可以创建Stock类型的变量(也可以说是Stock的对象)
**/
class Stock
{
private:
std::string company;
double share_value;
double total_value;
long share;
void set_tot(){total_value = share *share_value;};
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();
};
#endif /* Stock_hpp */
简要说明:
1.class关键字指出这些代码的作用:定义了一个类设计
2.Stock是这个类的类型名(也可以理解为类名;
3.通过这个声明,我们可以创建Stock类型的变量(也可以说是Stock类型的对象)
4.private和public则分别是接口中的私有部分和公有部分
1.访问控制
关键字private和public对类成员的访问控制,我们可以通过类的对象来访问公有部分,但是访问私有成员则只能通过公有成员函数。比如,我们想修改Stock类的total_value成员,只能通过Stock的成员函数。因此公有成员函数是程序 和 对象的私有成员之间的桥梁,提供了对象和成员之间的接口。防止程序直接访问数据被称为数据隐藏 。
C++还提供了第三个访问控制关键字protected
。类的成员可以是数据类型,也可以是函数。
2.控制对成员的访问:公有还是私有
无论类成员是数据成员还是成员函数,我们都可以在类的公有部分或者是私有部分中声明它。由于隐藏数据是OOP主要目标之一
,因此数据项通常放在私有部分,组成类接口的成员函数放在公有部分。如上面的代码,我们可以把成员函数放在私有部分中,此时我们不能直接通过程序调用这些函数,但是我们可以通过公有部分中的成员函数来访问它们。
在C++中,类与结构体具有相同的特性,它们之间的唯一区别就是:
结构体默认访问类型是public公有部分,类默认访问的是private私有部分。
我们通常使用类来实现类描述,而结构体通常只用来表示纯粹的数据对象。
二、实现类成员函数
我们在类声明中声明成员函数的函数原型之后,还需要实现对应的函数。成员函数的定义与常规函数的定义非常相似,他们也有函数头和函数体,也有返回类型和参数。但是他们还有两个特殊的标识特征:
1.定义成员函数时,使用作用域解析运算符(::)来标识函数所属的类
2.类方法可以访问类的private组件。
如下:
void Stock :: update(double price)
1.我们定义的update( )函数是Stock类成员
2.此外,我们还可以在其它的类中也定义一个名为update( )
的成员函数,例如,People( )类中的update( )函数的函数头为:
void People :: update(double peice);
也就是说,作用域解析运算符确定了方法(函数)定义对应的类的身份,函数update( )
具有类作用域(class scope)
,Stock
类的其它成员不必再使用作用域解析运算符就可以使用update( )
方法,这是因为他们属于同一个类,update( )
是可见的
类方法的完整名称中包括类名,Stock :: update( )
是函数的限定名(qualified name)
;而update( )
是全名的缩写,是非限定名(unqualified name ),
它只能在类作用域中使用。
请看如下代码:
#include "Stock.hpp"
#include <iostream>
using namespace std;
#pragma mark --
/**函数void acquire(const std::string & co ,long n, double pr);的实现**/
void Stock::acquire(const std::string &co, long n, double pr)
{
company = co;
if (n > 0)
{
cout << "Number of shares can’t ne negative;"
<< company
<< "Share set to Zero."
<< endl;
share = 0;
}
else
{
share = n;
}
share_value = pr;
set_tot();
}
#pragma mark --
/**函数void Stock::buy(long num, double price)的实现**/
void Stock::buy(long num, double price)
{
if (num < 0) {
cout << "Number of shares purchase can't be negative."
<< "Transaction is aborted ;"
<< endl;
}
else
{
share += num;
share_value = price;
set_tot();
}
}
void Stock:: sell(long num, double price)
{
if (num < 0)
{
cout << "Number of shares sold can't be negative."
<< "Tansaction is aborted."
<< endl;
}
else if(num >share)
{
cout << "You can't sell more than you have!"
<< "Transaction is aborted ."
<< endl;
}
else
{
share_value = price;
set_tot();
}
}
void Stock:: update(double price)
{
share_value = price;
set_tot();
}
void Stock::show()
{
cout << "Company:" << company
<< "Shares :" << share
<< endl
<< "Share Price: $" << share_value
<< "Total Worth: $" << total_value
<< endl;
}
1.成员函数说明:
4个成员函数设置或者重新设置了total_value
成员值,这个类并非将计算部分的代码编写了四次,而是让每个使用到的函数都去调用set_out( )
函数。set_out( )
只是实现代码的一种方式,不是公有接口的组成部分,所以在这个类中将它声明为私有成员函数(即:编写这个类的人可以使用,但编写代码使用这个类的人不能使用
)。这种方式的好处在于通过函数调用,提高代码的重用率,同时在修改起来也比较容易。
2.内联函数
定义位于类声明中的函数都将自动成为内联函数,因此,如上代码,Stock :: set_tot()
是一个内联函数。
类声明常将短小的成员函数作为内联函数,set_tot()
符合要求。
此外,也可以在类声明之外定义成员函数,并将其成为内联函数。只需要在类实现部分中定义函数时使用inline
限定符即可。
如下:
class Stock
{
private:
...
void set_tot();
public:
...
...
};
inline void Stock::set_tot()
{
total_value = share *share_value;
}
内联函数的特殊规则要求在每个使用他们的文件中都对其进行定义,确保内联定义对多文件程序中的所有文件都是可用的。。最简单的方法就是:将内联定义放在定义类的头文件中
。
根据改写规则:在类声明中定义方法等同于用原型替换方法定义,然后在类声明的后面讲定义改写为内联函数
。
3.方法使用哪个对象?
如下代码:
Stock kate,joe;//创建两个Stock对象
kate.show();//1.
joe.show();//2.
第一条语句调用kate
对象的show()
成员,这意味着show()
将shares
解释为 kate.shares
,将share_value
解释为kate.shares
。同理,第二条也如此。
注意:
调用成员函数时,它将使用被用来调用它的对象的数据成员
4.使用类
#include <iostream>
#include "Stock.hpp"
using namespace std;
int main(int argc, const char * argv[]) {
Stock class_obj;
class_obj.acquire("GuPiao007", 20, 12.12);
class_obj.show();
class_obj.buy(10, 18.88);
class_obj.show();
class_obj.sell(400, 20.11);
class_obj.show();
class_obj.buy(8888, 40.123);
class_obj.show();
class_obj.sell(3000000, 0.111);
class_obj.show();
return 0;
}
输出结果:
Number of shares can’t negative;GuPiao007
Share set to Zero.
Company:GuPiao007Shares :0
Share Price: $12.12Total Worth: $0
Company:GuPiao007Shares :10
Share Price: $18.88Total Worth: $188.8
You can't sell more than you have!Transaction is aborted .
Company:GuPiao007Shares :10
Share Price: $18.88Total Worth: $188.8
Company:GuPiao007Shares :8898
Share Price: $40.123Total Worth: $357014
You can't sell more than you have!Transaction is aborted .
Company:GuPiao007Shares :8898
Share Price: $40.123Total Worth: $357014
Program ended with exit code: 0
在前面,我们定义和实现了成员函数之后,就会使用到这个类。比如,我们在main.cpp
类中使用Stock
类中公有部分的成员函数时,就需要先导入Stock
类的头文件 。之前,我们在使用cin
和cout
方法时,就导入了它们所在类的头文件iostream
。如下:
#include <iostream>
#include "Stock.hpp"
当然,你会发现它们两个有所区别,一个使用< >
来包括头文件名,一个使用" "
来包括头文件名。它们的区别就是:前者用于导入系统所有类的头文件,而后者用于导入程序员自己创建类的头文件
。
说明:
1.在上面的代码中,
class_obj
是通过Stock类的类名创建的Stock类的对象。用一个例子来说明类与对象的关系,就是:类就好比是永辉超市集团,而对象就是我们所见到的永辉超市
。当然,这个例子比喻得比不是十分恰当。
2.我们在使用Stock
类并编译时,一定要确保使用它的类和Stock.cpp
一起编译,并确保Stock.hpp
在当前文件夹内。
5.总结
提供类声明
1.指定类设计的第一步是提供类声明,类声明和结构声明类似可以包括数据成员和结构成员。
2.声明通常分为两部分:私有部分
和公有部分
。私有部分中声明的成员只能通过成员函数进行访问;声明在公有部分中的成员可以被使用类对象的程序直接访问。
3.一般类声明的格式如下:
class className {
private:
data member declarations
public:
member function prototypes
};
4.公有部分的内容构成了设计的抽象部分:```公有接口```。将数据封装到私有部分中可以保护数据的完整性,这被称为```数据隐藏```。
实现类成员函数
指定类设计的第二步是实现类成员函数。可以在类声明中提供完整的函数定义,而不是函数原型。但是通常的做法就是单独提供函数定义(除非函数非常小)。在这种情况下,我们需要使用作用域解析运算符来指出成员函数属于哪个类。看个例子:
LOL
类有个doubleKill()
成员函数,这个成员函数返回int
类型数据,则该成员函数的函数头如为:int LOL::doubleKill()
创建类的对象
创建一个类的对象,就是将该类进行实例化。具体的创建方法为:
className classObj;
,类对象通过成员运算符句点来调用类的成员函数,比如:
className classObj;
classObj.memberFunc();