第三章
- 面向对象的本质是什么?
- C++基本数据类型
1 OPP编程本质是什么?
面向对象编程本质:设计并扩展自己的数据类型。
2 C++基本数据类型
代码即是正义 

【整型】
内置C++类型分两种:基本和复合类型
基本类型包括整数、浮点数;复合类型包括数组、字符串、指针、结构等。
整型(小->大):bool、 char、 signed char、 unsigned char、 short、 unsigned short、 int 、unsigned int、 long、unsigned long
举例:假设char为1byte,则unsigned char 0~255,而signed char -128~0~127 。虽然对于一个字节都是2^8=256个数,但是就数值表示范围而言,无符号unsigned要比有符号signed类型大得多。
【补充1】sizeof() 与 strlen()
sizeof() 与 strlen()的联系与区别效率 | 作用 | 参数 | ||
sizeof(形参) | 运算符、关键字 | 编译器在编译阶段执行,效率高 | 用于测量类型或对象所占的内存字节,可以和除法组合用来测出数组中成员的个数或者字符串个数等。 | 可以是 任何类型,且它本身也可以作为形参使用 |
unsigned int strlen(const char* string) | 函数 | 编译器在运行阶段,该函数被调用到才执行,效率低 | 返回字符串的个数,遇到第一个'\0'结束且字符'\0'不包含在内。 | 必须是const char* 类型的形参,且它本身也可以作为形参使用 |
运行:
代码:VS13
#include <iostream>
#include <string>
using namespace std;
struct Stu
{
int a;
char b;
long c;//long在WIN7 VS13中测试居然是4bytes!!!
};//我猜是20bytes---打脸,实际结果是12bytes
class Stu2
{
private:
int m_a;
char m_b;
long m_c;
public:
void set(int a,char b,long c);
};
void Stu2::set(int a, char b, long c){
m_a = a;
m_b = b;
m_c = c;
}
int main()
{
Stu test = {1,'2',3};
Stu2 test2;
test2.set(4,'5',6);
string str = "haha";
const char* cstr = "haha";
const char* cstr2 = "hahaxixi";
int array[] = { 1, 2, 3, 4, 5, 6 };
/*【1】sizeof可对结构体变量、类示例化的对象的子字节大小测量*/
cout << "结构体变量 sizeof(test) = " << sizeof(test) << endl;
cout << "类实例化的对象 sizeof(test2) = " << sizeof(test2)<<endl;
int a = 7; char b = '8'; long c = 9;
cout << "int a =" << sizeof(a) <<" ";
cout << "char b =" << sizeof(b) << " ";
cout << "long c =" << sizeof(c) << " "<<endl;
cout << "sizeof ((int a = 7) + (char b = '8') + (long c = 9))为" << sizeof(a) + sizeof(b) + sizeof(c) << endl;
/*【2】sizeof可对string类型的变量进行字节大小测量吗?测验知,可以。但string类的变量所占字节远大于const char*定义变量所占的4个字节*/
cout << "/*******************************************************/"<<endl;
//尝试看看string类型的变量是否可以具体计算出其字节大小或者字符个数
cout << "string类型变量 sizeof(str) = " << sizeof(str)<<endl;
//cout << "string类型变量 strlen(str) = " << strlen(str) << endl;//报错:string类型无法转换到const char*类型
cout << "const char*类型变量 sizeof(cstr) = " << sizeof(cstr)<<endl;
cout << "const char*类型变量 sizeof(cstr2) = " << sizeof(cstr2) << endl;
/*【3】strlen只可以对const char* 类型变量进行测量,即strlen()只可以测量字符串中字符的个数*/
cout << "/*******************************************************/" << endl;
//cout << "string类型变量 strlen(str) = " << strlen(str) << endl;//参数str回报错,因为strlen()只接受const char*类型的参数
cout << "const char*类型变量 strlen(cstr) = " << strlen(cstr) << endl;
cout << "const char*类型变量 strlen(cstr2) = " << strlen(cstr2) << endl;
/*【4】strlen本身可作参数使用*/
cout << "/*******************************************************/" << endl;
//strlen本身能否作为参数使用呢?试试看
cout << "结构体变量 sizeof(strlen(cstr)) = " << sizeof(strlen(cstr)) << endl;//显然可以
/*【5】数组成员的个数sizeof(array)/sizeof(int)*/
cout << "/*******************************************************/" << endl;
cout << "sizeof(array)/sizeof(int) 即数组成员的个数为:" << sizeof(array) / sizeof(int) << endl;;
system("pause");
return 0;
}
【补充2】将信息保存到计算机中的一般型策略
为将信息存储到计算机中,谨记两条准则:存什么?存哪里? 一般采用的策略是:使用变量
变量类型 | 变量值 | 变量名 |
代指内存单元 | ||
举例:int a = 10; | ||
int类型 | 10 | a |
这些语句告诉程序,去找一块存储整型变量的内存单元 | 把5复制进去, | 并将该内存单元标识为a,以供访问。 |
标识数据的其她方法: | & | 指针 |
注意:定义变量名时,只能是字母、下划线、数字,且不能用数字开头,不能用C++关键字作为名字等 |
--- 变量三要素:类型、值、名
---常用命名风格:my_lucy or myLuck
---常用前缀:str(字符串)、p(指针)、c(单字符)、b(表示布尔)、m_happy(类成员变量)
【补充3】预处理
预处理指令:#include #define等
在C++编译过程中,先将源代码传递给预处理器进行预处理。再编译、连接、运行。
【补充4】变量、数组、结构体 在C++中的不同初始化方法
C++11 大括号{}初始器可用于任何数据类型(等号可用可不用),这是一种通用初始化语法。
运行结果:
代码:
#include <iostream>
#include <string>
using namespace std;
struct Stu
{
int a;
char b;
long c;//long在WIN7 VS13中测试居然是4bytes!!!
};//我猜是20bytes---打脸,实际结果是12bytes
class Stu2
{
private:
int m_a;
char m_b;
long m_c;
public:
void set(int a,char b,long c);
};
void Stu2::set(int a, char b, long c){
m_a = a;
m_b = b;
m_c = c;
}
//非正文
void sizeofStrlen()
{
Stu test = {1,'2',3};
Stu2 test2;
test2.set(4,'5',6);
string str = "haha";
const char* cstr = "haha";
const char* cstr2 = "hahaxixi";
int array[] = { 1, 2, 3, 4, 5, 6 };
/*【1】sizeof可对结构体变量、类示例化的对象的子字节大小测量*/
cout << "结构体变量 sizeof(test) = " << sizeof(test) << endl;
cout << "类实例化的对象 sizeof(test2) = " << sizeof(test2)<<endl;
int a = 7; char b = '8'; long c = 9;
cout << "int a =" << sizeof(a) <<" ";
cout << "char b =" << sizeof(b) << " ";
cout << "long c =" << sizeof(c) << " "<<endl;
cout << "sizeof ((int a = 7) + (char b = '8') + (long c = 9))为" << sizeof(a) + sizeof(b) + sizeof(c) << endl;
/*【2】sizeof可对string类型的变量进行字节大小测量吗?测验知,可以。但string类的变量所占字节远大于const char*定义变量所占的4个字节*/
cout << "/*******************************************************/"<<endl;
//尝试看看string类型的变量是否可以具体计算出其字节大小或者字符个数
cout << "string类型变量 sizeof(str) = " << sizeof(str)<<endl;
//cout << "string类型变量 strlen(str) = " << strlen(str) << endl;//报错:string类型无法转换到const char*类型
cout << "const char*类型变量 sizeof(cstr) = " << sizeof(cstr)<<endl;
cout << "const char*类型变量 sizeof(cstr2) = " << sizeof(cstr2) << endl;
/*【3】strlen只可以对const char* 类型变量进行测量,即strlen()只可以测量字符串中字符的个数*/
cout << "/*******************************************************/" << endl;
//cout << "string类型变量 strlen(str) = " << strlen(str) << endl;//参数str回报错,因为strlen()只接受const char*类型的参数
cout << "const char*类型变量 strlen(cstr) = " << strlen(cstr) << endl;
cout << "const char*类型变量 strlen(cstr2) = " << strlen(cstr2) << endl;
/*【4】strlen本身可作参数使用*/
cout << "/*******************************************************/" << endl;
//strlen本身能否作为参数使用呢?试试看
cout << "结构体变量 sizeof(strlen(cstr)) = " << sizeof(strlen(cstr)) << endl;//显然可以
/*【5】数组成员的个数sizeof(array)/sizeof(int)*/
cout << "/*******************************************************/" << endl;
cout << "sizeof(array)/sizeof(int) 即数组成员的个数为:" << sizeof(array) / sizeof(int) << endl;;
}
int main()
{
//非正文
//sizeofStrlen();//正确
//void sizeofStrlen();//错误//为什么加了void没有任何输出而不加则能正常使用呢?void到底什么作用?
/*
void的字面意思是空类型,void *的意思是空类型指针,void 不是一个真正的类型,我们在声明变量的时候从来不会像下面这样声明:
void a;
如果我们写了一行这样的代码,某些编译器会直接报错,有些则不会,但也没有任何意义。
void真正的用途在下面两个方面:
对函数返回值的限定
对函数参数的限定
比如,函数没有返回值,那么函数可能会声明成这样:void fun(int a);
如果函数有返回值,但是函数没有参数,那么函数的可能会声明成这样:int fun(void)。
以上的情况都是很好理解的。下面介绍void *的一些用法。
*/
//正文:
/*【1】C++变量、数组、结构体赋值其他方法*/
//变量
int a{ 7 }; cout << " a = " << a << " ";
int b = { 14 }; cout << " b = " << b << " ";
//{}中什么也不写,表示初始化为0
int c{}; cout << " c = " << c << " ";
int d = {}; cout << " d = " << d << " "<<endl;
//数组
int array2[]{ 6, 5, 4, 3, 2, 1 };
cout << " 数组array2 = ";
for (int i = 0; i < sizeof(array2) / sizeof(int); i++)
cout << array2[i];
//结构体
Stu e{ 1, '2', 3 }; cout << " 结构体 " << e.a << " " << e.b << " " << e.c << " " << endl;
/*【2】补充:如何输出字符串、数组*/
//方法1:
char* cstr = "xox";
cout << " 字符串 ";
for (; *cstr != '\0'; cstr++)
cout << *cstr;
cout << endl;
//方法2:
int array[] = { 6, 5, 4, 3, 2, 1 };
cout << " 数组array = ";
for (int i = 0; i < sizeof(array) / sizeof(int); i++)
cout << array[i];
//错误例子:
//int array[]{1, 2, 3, 4, 5, 6}; int* p = array;
//cout << " 数组array = ";
//while (*p++ != '\0') cout << *p;//报错//原因:array是数组并不是字符串,她的最后一个的后一个成员array[6]其值是一个未知数
system("pause");
return 0;
}
【补充5】溢出
无符号、有符号类型所表示的最大数值范围 以及 发生上溢或者下溢时的情况:
自加的话,
无符号类型变量取值范围:0 -> max - 1 -> 0 循环下去
有符号类型变量取值范围:-|min| -> 0 -> max - 1 -> -|min| 循环下去
运行结果:
代码:
#include <iostream>
#include <string>
using namespace std;
void yiChu()
{
/*【1】无符号、有符号类型所表示的最大数值范围 以及 发生上溢或者下溢时的情况*/
//自加的话,无符号类型变量取值范围:0 -> max -> 0 循环下去 有符号类型变量取值范围:-|min| -> 0 -> max - 1 -> -|min| 循环下去
//无符号 上溢
unsigned short Num0, Num1 = 65535, Num2 = 65536, Num3 = 0;
Num0 = Num1 + 1;
cout << "无符号类型:" << endl;
cout << "Num1 = " << Num1 << " " << "Num2 = " << Num2 << " " << "Num3 = " << Num3 << " " << endl;
cout << "Num0 = Num1 + 1 则 Num0 = " << Num0 << endl;
//有符号 上溢
short Num4 = -32768, Num5 = 32767, Num6 = 32768;
cout << "有符号类型:" << endl;
cout << "Num4 = " << Num4 << " " << "Num5 = " << Num5 << " " << "Num6 = " << Num6 << " " << endl;
cout << "Num5 + 1 = " << short(Num5 + 1) << endl;
//cout << "Num5 + 1 = " << Num5 + 1 << endl;//没有报错 但是结果不是想要的//解决方法:方法1---定义一个short的临时变量temp,temp = Num5 + 1 方法2---强制类型转换 (short)Num5 + 1
//原因:本来Num5是short类型的,结果写成这样Num5 + 1之后,因为没有明确给出Num5 + 1的类型,所以计算机会按自己最舒服的int来默认Num5 + 1的类型,所以本该输出为0的却正常+1输出
}
int main()
{
//正文
yiChu();
system("pause");
return 0;
}
【补充6】计算机最喜欢哪种类型的值?
显然int是计算机认为最舒服的值。
“通常,int被设置为对目标计算机而言最为‘自然’的长度。自然长度指的是计算机处理起来效率最高的长度。如果没有非常有说服力的理由来选择其他类型,则应使用int。” ---C++ Primer Plus 第六版 3.1.5选择整形类型
【补充7】如何用十进制、八进制、十六进制输出一个数?
运行结果:
代码:
#include <iostream>
#include <string>
using namespace std;
void cou()
{
/*【1】不论十进制也好,八进制、十六进制也罢,最终都是以二进制存放在计算机里*/
int a = 15, *p = &a;
cout << *p << "(十进制)" << endl;
cout << oct << *p << "(八进制)" << endl;
cout << hex << *p << "(十六进制)" << endl;
}
int main()
{
//正文
cou();
system("pause");
return 0;
}
【补充8】不同操作系统对基本类型宽度定义不同
不同OS对int等类型的宽度 表示不同,老式IBM PC机int宽度2bytes,现在的常见OS将int宽度表示为4bytes。
【char类型:字符和小整数】
char类型是整型的一种,专为存储字符(如字母和数字)而设计。注意在数值上,unsigned char 和 signed char的差异。(前者:0~256,后者:-128~127)
”char类型是整型的一种,专为存储字符(如字母和数字)而设计的。它足够长,能表示目标计算机系统中所有的基本符号---所有的字母、数字、标点符号等。实际上,很多系统支持的字符都不超过128个,所以一个字节足够用。因此,虽然char常被用来处理字符,但也可以用作比short更小的整型。"---C++ Primer Plus 第六版 3.1.8 char乐享:字符和小整数
疑问:如何在C++中使用C代码的风格来解决判断字符是否相等的问题???
---已尝试用strcmp(),但是仍不奏效!
运行结果:
代码:
#include <iostream>
#include <string.h>
#include <string>
using namespace std;
void char_()
{
/*【01】cin、cout都是智能对象 cout.put()只可以对单个字符进行输出,cout既可以输出单个字符也可以输出字符串。*/
//并且单个字符经过cin输入之后可以参与算术运算,运算结束后,当被cout输出时,以字符形式输出到屏幕上
//cin输入时字符会自动转换成相应的ASCII码值被处理,cout输出时又会根据ASCII表自动转成相应字符输出
char ch, temp = '0';
int num = -1;
while (1)
{
cout << "请输入一个字符: ";//输入A 下面会用到
cin >> ch;//cin之后的ch已经转换成整型数,可进行算术运算,单cout输出时会自动转换成字符,除非先进行算术运行然后再cout。
cout << "输入的字符为:";
cout<<ch;
printf("---ASCII码值为:%d\n", ch);
//A 65 Z 90
cout.put(ch);
//算术运算
ch = ch + 25;
cout << "后第25个字母为:";
cout.put(ch);
printf("---ASCII码值为:%d\n", ch);
cout << "*********************" << endl;
//算术运算
ch = ch - 25;
cout <<"ch - 25 = "<< ch << endl;
//犯的这两个错误没有报错,但是运行结果都不是我想要的,第一个想了一会才想明白原因,第一个通过断点调试才解决。如下:
//error1:char ch;if(ch == '0'){...} //原因:对于C语言风格的char而言,string类中的==运算符它是不能使用的,可以使用C语言风格的函数strcmp(&ch,&...)进行比较
//error2:char ch;if (ch == 48){...} //原因:致命错误 逻辑上,我把判断语句放在了ch = ch + 25;语句后面 导致ch的值+25 !!!
}
}
int main()
{
char_();
system("pause");
return 0;
}
【浮点数】
- 何为浮点数?
通过缩放因子来移动小数点的位置,进而改变原数值的数叫做浮点数。
例如:3.14 基准值是3 若缩放因子为10^3的话 则小数点右移3位 则结果为3140; 反之若缩放因子为10^-3的话,则左移。
运行结果:
代码:
#include <iostream>
#include <string.h>
#include <string>
using namespace std;
int main()
{
//一些浮点数
cout << "一些浮点数:" << endl;
cout << "2.66e2=" << 2.66e2 << endl;
cout << "6.99e+3=" << 6.99e+3 << endl;
cout << "8.88E-4=" << 8.88E-4 << endl;
cout << "9.11e-31=" << 9.11e-31 << endl;
system("pause");
return 0;
}
【浮点型】
若不强调类型,对于浮点数C++会默认为double类型。
在精度上,float类型要比double类型低。若在小数点后的某一位上(float已经精确不到但是double能够精确到的位置上),将浮点移到该位置上,float(double等等也类似)的精度只能表示到该位(其实通过下面的代码测试,在VS13 C++11版本中,无论float、double、long double,她们都只精确到有效位第六位)之前,若在该位之后对float类型的浮点数进行+ or - (要考虑到进位和四舍五入进位的情况)则该浮点数不变。
例子:
运行结果:
代码:
int main{
cout << "float所占字节数:" << sizeof(float) << endl;//4bytes 2^32 = 4294967296 有符号:-2147483648 ~ 2147483647
float a = 2147483646,b = 0.0f;
cout << "float a = 2147483646 则a = " << a << endl;//输出 2.14748e+009
//显然,从上面的结果可见float类型的变量只精确到有效位的第6位
//那么,我将对有效位第7位进行+法 看看结果是不是有什么变化(不产生进位,也不产生四舍五入的进位)
b = a + 1000;
cout << "float b = a + 1000; 则b = " << b << endl;//结果没有变化 输出 2.14748e+009
system("pause");
return 0;
}
【运算符】
+ - * / %
/ 取整取余结合使用得出多位数的 各个位上的位数
% 两个操作数必须是整数 若 % 的两个操作数中有一个负数,取模结果仍为正
运行结果:
代码:
#include <iostream>
#include <string.h>
#include <string>
using namespace std;
int main()
{
int a = 0;
a = 20 % (-11);
cout << a << endl;
cout << (20 / 9) << endl;
cout << (20.0 / 9) << endl;//精度被限制为6位有效数字
float b = 3.0;
b = 20 / b;
cout << b << endl;//精度被限制为6位有效数字
double c = 3.0;
c = 20 / c;
cout << c << endl;//精度被限制为6位有效数字
float d = 3.0;
d = 20 / d;
cout << d << endl;//精度被限制为6位有效数字
system("pause");
return 0;
}
【强制类型转换】
没问题:精度小的类型 -> 精度大的类型
存在问题:精度大的类型 -> 精度小的类型
哪些问题: 精度降低(如double -> float)、丢失小数部分(如float -> int)、编译器不会报错但是错误很严重:截断常量值(如int -> short)
运行结果:
代码:
#include <iostream>
#include <string.h>
#include <string>
using namespace std;
int main()
{
cout << "sizeof(short) = " << sizeof(short) << " sizeof(int) = " << sizeof(int) << endl;
//sizeof(short) = 2 --- -32678 ~ 32677
//sizeof(int) = 4 --- -2147483648 ~ 2147483647
//下面让int -> short 看看截断常量值是什么情况
int a = 2000000000;
short b = 20000;
b = a;//结果:-27648 //常量值显然被截断
cout << "b = " << b << endl;
system("pause");
return 0;
}
【const限定符】
使用关键字const比使用宏定义define能够更好地处理符号常量。
const作用:定义常量、修饰函数参数、修饰函数返回值。被其修饰的东西可以受到强制保护,以预防意外改动,能提高代码健壮性。
与define相比const的优点:
- const能指明数据类型(包括复杂的数据类型),而define无法指明数据类型。
- 某些集成化的调试工具可以对const常量进行调试,但不能对宏常量进行调试。