文章目录
从最基本的层面理解,数据结构是把一组相关的数据元素组织起来然后使用它们的策略和方法。而类就是其中一种数据结构。
C++允许用户以类的形式自定义数据类型,string、istream、ostream等也就是以类的形式定义的。
定义Sales_data类型
尽管我们还无法写出完整的Sales_data类,但是可以尝试着把那些数据元素组织到一起形成一个简单的类。初步进行使用。
还有这边建议不要初始化类放在定义的后面:
如:
struct Sales_data{/* */}accum,trans,*p; //1
建议是改成下面的:
struct Sales_data{/* */};
Sales_data accum,trans,*p;
还有一点就是切记再1处要记得加上分号,重点错误地。
类数据成员
类体定义类的成员,我们的类只有数据成员,类的数据成员定义了类的对象的具体内容,每一个对象都有自己的一份数据成员拷贝,修改一个对象的数据成员,不会影响其他的Sales_data的对象。
而对于类内初始值的限制与之前的介绍类似,详情可见我本篇专栏的文章2.2处,有进行相关的介绍,现在稍微提一句,对于限制应该使用花括号放在等号右边如
int a = {0},而不能使用(),原因就在于()会进行强转,导致限制无效。
相同的,后续也将会介绍C++的另一个关键字class来定义自己的数据结构,这里稍微提一嘴。
使用Sales_data类
添加Sales_data对象
#include<iostream>
#include<string>
#include"Sales_data.h"
using namespace std;
int main()
{
Sales_data data1,data2;
return 0;
}
和原本的程序一致,就是需要先把头文件包含进来并且定义变量用于接受输入,和Sales_item类不同的是,新程序还包含了string的头文件,虽然没有进行使用。
Sales_data对象读入数据
string类型实际就是字符的序列,它的操作有>>、<<、==,功能分别是读入字符串,写出字符串,比较字符串。
如我们要计算自定义价格(承接上文的格式):
#include<iostream>
#include<string>
#include"Sales_data.h"
using namespace std;
int main()
{
Sales_data data1,data2;
int price1;
cin>>data1.units_sold>>price1;
data1.revenue=data1.units_sold*price1;
return 0;
}
相信大家也可以简单的看懂。
输出两个Sales_data对象的和
例如:
#include<iostream>
#include<string>
#include"Sales_data.h"
using namespace std;
int main()
{
Sales_data data1,data2;
int price1,price2;
cin>>data1.units_sold>>price1;
data1.revenue=data1.units_sold*price1;
cin>>data2.units_sold>>price2;
data2.revenue=data2.units_sold*price2;
cout<<data1.revenue+data2.revenue<<endl;
return 0;
}
编写自己的头文件
尽管可以所有的类都定义再函数体内,但是这样的类毕竟也受到了一些限制,所以,类一般都不定义在函数体内。当函数体外定义类的时候,在各个指定的源文件中只可能有一处有该类的定义。
为了保证各个文件中类的定义一致,类通常被定义在头文件中,并且所在的头文件名字应该和类的名字一致。
头文件一般包含那些只能被定义一次的实体,如类、const和constexpr变量(详情见之前的介绍),此处进行强调一次:
1.const用于修饰不能被修改的对象,但const对象的值通常在程序运行期间才能确定
2.constexpr用于修饰常量表达式或可返回常量表达式的constexpr函数,在编译时能确定值。
善于使用constexpr和const将会大大提升代码运行的效率
PS:头文件一旦改变,相关的源文件就必须重新编译以获取更新过的声明
预处理概述
为了确保头文件多次包含仍能安全工作的常用技术是预处理器,其实也就是#include ,当预处理器看到这个标志的时候,将会用到指定头文件的内容替代该#include
C++程序还有使用到的一项预处理技术是头文件保护符,头文件保护符依赖于预处理变量。预处理变量有两种状态:已定义和未定义。#define指令把一个名字设定为预处理量,另外两个指令则分别检查某个指令的预处理变量是否已经定义:#ifdef当且仅当变量已经定义时为真,#ifndef当且仅当变量未定义时为真,一旦检查结果为真,则执行后续操作直至遇到==#endif==为止。
这个常常用于两个地方
第一处:
用于头文件的多次包含问题
#ifndef SALES_DATA_H //判断这个宏是否被定义,如果已经被定义就不执行此处跳到#else或者#endif
#define SALES_DATA_H //定义这个宏,避免之后再次被定义
#include<string>
using namespace std;
struct Sales_data
{ /*
此处有 数据
*/
};
#endif
当然为了方便也有更简单的方法就是使用官方定义的宏
#pragma once
struct Sales_data
{ /*
此处有 数据
*/
};
这样子即可。
第二种用法就是当面对多种系统的时候,我们写的软件为了兼容也应该有这种定义,这种一般也就是通过宏定义来判断此处是否是所对应的系统。
此处还有一点就是关于#if和#ifdef的区别理解:
#ifdef指令说明:如果预处理器已经定义了后面的标识符,那么执行所有指令并编译C代码,直到下一个#else或者#endif出现为止(无论#else和#endif谁先出现)。如果有#else指令,那么,在未定义标识符时会执行#else和#endif之间的所有代码。
#if说明:#if指令更像常规的C中的if,#if后跟常量整数表达式。如果表达式为非零值,则表达式为真。在该表达式中可以使用C的关系运算符和逻辑运算符。且可以使用#elif指令扩展if-else序列
PS:预处理变量无视C++中关于作用域的规则