文章目录
- 前言:
- 1 过程性编程和面向对象编程
- 2 抽象和类
- 2.1 类型是什么
- 2.2 C++中的类
- 2.3 实现类成员函数
- 2.4 使用类
- 3 类的构造函数和析构函数
- 3.1 声明和定义构造函数
- 3.2 使用构造函数
- 3.3 默认构造函数
- 3.4 析构函数
- 4 this指针
- 5 对象数组
- 6 类的作用域
- 6.1 作用域为类的常量
- 6.2 作用域内枚举
- 7 抽象数据类型
- 8 总结
- 9 参考
前言:
面向对象编程(OOP)这是一种特殊的,设计程序的概念性方法,下面是他的一些特性:
- a.抽象
- b.封装和数据隐藏
- c.多态
- d.继承
- e.代码的可重用性
C++与C最大的区别就是提出了类,以上的特点都是通过类来展开的,这一章将重点介绍“类”这个重要概念。
1 过程性编程和面向对象编程
所谓过程性编程是从代码实现的角度,来进行编程,用多个函数来解决复杂的问题;而面向对象编程,首先从用户的角度来考虑对象,描述对象所需的数据,以及描述用户与数据交互的操作。完成对接口的描述后,需要确定如何实现接口和数据存储。最后,创建出程序,这便是C++相对于C的进步。
这样说有点晦涩,举个例子,你是个仓库管理员,仓库里放满了车子,你想编个程序进行管理,用C如何实现,我会用main()函数调用一个函数来获取输入,调用另一个函数,对车子停车时长进行计算,用第三个函数来显示结果;这些只是对数据的处理,我们后续还要进行增删查改,以及对数据的存储,还要创建另外的数组。这种方法太过死板;如果C++出马,首先他会创建一个对象记录车的各个数据,还要考虑如何处理这些数据,这样后续进行增删查改也更加灵活方便。
2 抽象和类
实际要解决的问题千奇百怪,最好的解决方法是化繁为简,以不变应万变。简单和抽象是解决复杂性问题的主要方法,即将问题的本质抽象出来,根据问题的特征来解决问题。
2.1 类型是什么
类型,比如定义你的理想型,肤白貌美,有钱,这是特性的描述,有人喜欢说话声音轻柔的,善解人意的,这就是你理想型的行为特征,所以类不仅有数据成员,还有方法成员。
2.2 C++中的类
在C++中类不仅是一个概念,更是一种解决问题的工具,它将数据表示和操纵数据的方法组合成一个完整的包。书中用一个表示股票的类,类中有2个部分:
1)股票信息:公司名称,股票数量等;
2)操作信息:增持,抛售股票等;
总结一下,类声明提供了类的蓝图,方法定义了实现的细节。
- a.访问控制
在类的声明中有两个关键字,private与public,描述了对类成员的访问控制。使用类对象的程序只能访问public部分,但只能通过公有成员函数来访问对象的私有成员。 - b.控制对成员的访问:
一般来说方法,成员函数的权限是private, 组成类接口的成员函数放在公有部分,其他成员都可以调用公用的接口。C++出于数据隐藏的目的,其他类成员只能通过类接口来访问类成员,否则无法进行访问。
2.3 实现类成员函数
通常在一个头文件中对类进行声明,而其中类的接口的实现在另一个源文件中实现,书中的示例就是将类方法全部写在另一个源文件中。详见股票程序。
2.4 使用类
在头文件中定义了类,并在一个源文件中定义了类接口的实现方法,接着就是在主函数中对类进行调用了,书中usestock00.cpp对类进行了调用,验证了程序的正确性。
3 类的构造函数和析构函数
类被设计出来有一个初衷:隐藏数据!所以数据部分的访问状态是私有的,这样程序就不能直接访问数据成员。为此,C++专门提供了一类特殊的成员函数——类构造函数,专门用于构造新对象,将数值赋予给他们的成员。而析构函数与构造函数的功能相反,实在程序的生命周期结束的时候,将他们的成员置空删除。
3.1 声明和定义构造函数
构造函数的声明种有一些形参,这些形参表示的不是类成员,而是要赋予给类成员的数值,要注意区别参数名与类成员名,为了做区分,通常将类成员名加上m_的前缀。
3.2 使用构造函数
创建了类之后,需要用构造函数,对类对象赋予初始值,赋予初始值有两个方法,
方法一:显示地调用
Stock A = Stock(“A”,1,1.0);
方法二:隐式地调用
Stock B(“B”,2,2.0);
3.3 默认构造函数
所谓默认的构造函数,就是未提供显式初始值时,用来创建对象的构造函数。在程序中当且仅当没有定义任何构造函数时,编译器才会提供默认构造函数。如果提供了非默认的构造函数,直接声明类对象会出错。
例如:
Stock(const char* co,int n,double pr)
Stock stock1
此时,声明的stock1就会出错。
除了不写构造函数,有2种方法可以构造默认函数,以上述的Stock为例子。
方法一:给已有的构造函数的所有参数提供默认值
Stock(const string &co = “Error”,int n = 0,double pr = 0.0);
方法二:通过函数重载来定义一个构造函数
Stock::Stock(){
company = “error”;
shares = 0;
share_val = 0.0;
total_val = 0.0;
}
3.4 析构函数
用构造函数创建对象后,程序负责跟踪对象,直到其过期为止。对象过期时,程序会自动调用一个特殊的成员函数,负责完成清理工作。析构函数与构造函数同名,但是函数之前加上了一个~以作区分。析构函数内不需要做任何事情,要是没有写析构函数,程序会提供一个默认的析构函数。
4 this指针
每个类成员都只涉及一个对象,当涉及两个对象时,就需要使用C++的this指针。这个概念类似于我之前学习python的self函数代指自身。
书中有一个示例:topval()方法用来比较两个股票的总价,比较方法的原型是:
const Stock & topval(const Stock & s) const;
将其中股价较高的那一支股票赋值给top,
top = stock1.topval(stock2);
这个函数隐式地访问stock1,显示地访问stock2,此时就会发现,你只能返回引用的s,以上智能返回stock2,而不能返回stock1,C++提供了解决这种问题的方法——this指针,this被作为隐藏参数传递给方法。
补充:每个成员函数(包括构造函数和析构函数)都有一个this指针,this指针指向调用对象,如果方法需要引用整个调用对象,则可以使用表达式*this。
5 对象数组
在实际应用中,用户通常要创建同一个类的多个对象,这些对象又都属于同一个类,这就类似于“数组“的概念。这个时候需要显示地调用构造函数,将对象的参数都输入进去。
举个例子:
const int len = 4;
Stock stocks[len]={
Stock(“A”,1,1),
Stock(“B”,2,2),
Stock(“C”,3,3),
Stock(“D”,4,4),
};
6 类的作用域
在类中定义的名称的作用域为整个类,作用域为整个类的名称只是在该类中是已知的。所以在不同类中使用相同的类成员名不会引起冲突。
6.1 作用域为类的常量
在类中如果要声明一个常量,直接const int x = 10;这样是不行的,在声明类中只是描述了对象的形式,并没有创建对象,所以在创建对象之前没有用于存储数值的空间。有2种方法可以实现常量的声明
1)在类中声明一个枚举:
class Barkey{
private:
enum{Months = 12};
double const[Months];
……}
2)用static定义常量:
class Barkey{
private:
static const int Months = 12;
double const[Months];
……}
6.2 作用域内枚举
传统的枚举可能存在一些问题,例如enum A {S,M,X,XL} enum B{S,M,X,L},这两个枚举量就存在冲突。为了避免这种冲突,C++11提供了一种新枚举,其枚举量的作用域为类。
enum class A {S,M,X,XL} ;
enum class B{S,M,X,L};
引用的时候就添加A::S,这样就能避免冲突。
7 抽象数据类型
书中举了一个卖股票的例子,这个stock类十分的具体,有股票的各种信息,也包含了对股票的各种操作。但是程序员也会用类表示抽象数据类型(Abstarct data type)。书中用类来对栈进行描述。见书中程序清单。
8 总结
首先,提供了类这个概念,私有数据成员存储信息,公有成员函数提供访问数据的唯一途径,类将数据和方法合成了一个单元,私有数据成员实现了数据隐藏。
另外介绍了两个十分重要的函数构造函数与析构函数,用来创建与销毁类,并介绍了默认的构造与析构函数。
希望成员对多个类进行应用,介绍了this的概念,用this指针设置成调用对象的地址,*this是该对象的别名。
9 参考
9.1 《C++ Primer Plus》