PoEdu - C++阶段班- Lesson02_C to C++
1 原生bool类型
c++里面的bool类型才是真正原生的true和faul,比如常见的大写的“BOOL”,它就不是原生的。
原生的与非原生的bool,它们的区别:
详细说下原生bool与非原生bool之间的差别:
_Bool 这个是c98之后加上的bool类型,和我们原生bool等同。
C++中,建议一直使用原生bool,它是最安全的类型。
补充一点:宏定义一个int类型的bool,之所以这么做,是因为0是false,1是true,在C++中,这种比对是有风险的,可以说是不正确的。
2 头文件的三种标准
在vs2015上默认建立一个项目,VS2015帮我们生成4个文件:
stdafx.h这个是微软给我们的一个大坑。
有可能会导致一个问题:预编译头会导致平台不兼容。
文件后缀cpp和c,编译器会选择不同的编译方式编译。
在以DomainOperatorDemo这个解决方案命名的工程中,生成的DomainOperatorDemo.cpp,有程序员直接改名为main.cpp。告诉别人main方法在这里。
在stdafx.h中,默认包含了3个头文件。我们可以直接在main函数中使用printf()。
其中还包含了tchar.h,这是微软给我们的一个坑,它是windows特定的头文件,它前面有个t,带有很强的平台特性。不要过于依赖这个头文件。
以c++中,stdio.h和cstdio功能一样。
3 补充预编译头:提问stdafx.cpp具体的作用是什么呢?
可以理解为微软的VC特有的文件,实际上我们可以完全的没有它,直接创建空项目。是给编译器用的,并不是我们所需要的。预编译头,想是给我们一定的便利,但并没有什么卵用。
4 域运算符
它的作用主要就是来解决一件事:
看示例:
变量不是最终的本质,本质是内存里的表述数据。
作用域访问符::
变量的覆盖原则:就近访问。谁最近,我就去找它。
命名空间与作用域:
在C语言中,我们了解到,变量的生命周期和作用域,就是看这个变量放在哪,外部的、全局的、局部的,局部的局部的等,在C中对变量的作用域控制力是很弱的。
所以在C++中,特意加入了一个权限概念:命名空间,加强了作用域的控制。除了全局空间,栈空间,又多了一个自已定义的命名空间。
当域作用符前面为空的时候,表示为全局空间,域作用符前面有名称的,就是命名空间
std是个什么样子的命名空间?看图:
如何自定义一个命名空间:
自定义命名空间除了解决变量重定义的问题,它还有其它的作用吗?答案是有的:工业编程里面,大的项目是很多程序员合作的结果,当另一个伙伴想要访问你一个同名的变量时,命名空间就能很好的分隔区分它们。
5 new&delete 运算符
前面讲到了全局,讲到了栈,现在说说“堆”:
c中我们学到2个操作函数是 malloc() 和 free()。C++中间添加了new 和 delete ;
#include <iostream> int main()
{
int *pNum = new int();
std::cout << *pNum; return ;
}
运行:100
在C语言中maloc()一定和free()对应使用,那么C++中也是:new一定对应delete使用。
#include <iostream> int main()
{
int *pNum = new int();
std::cout << *pNum;
delete pNum;
return ;
}
运行:100
再看:如果new一个数组呢,怎么释放?
#include <iostream> int main()
{
int *pNum = new int();
std::cout << *pNum; int *pArray = new int[]; delete pNum;
delete[] pArray;
return ;
}
运行:100
注意:new 和 delete 是运算符,它们不是函数。重要的说三遍!老师就在课堂里强调了三次。
6 什么条件下能够构成重载
看代码,我们在C中是这么写函数的:
#include <cstdio> void MyCoutInt(int num)
{
printf("%d", num);
} void MyCoutChar(char c)
{
printf("%c",c);
} void MyCoutFloat(float f)
{
printf("%f",f);
} void MyCoutString(char *str)
{
printf("%s", str);
} int main()
{ return ;
}
以上在C中,各个函数因为参数不同,而函数名也要不同,不然就重定义了。C++中,可以这样子写:
#include <cstdio> void MyCout(int num)
{
printf("%d", num);
} void MyCout(char c)
{
printf("%c",c);
} void MyCout(float f)
{
printf("%f",f);
} void MyCout(char *str)
{
printf("%s", str);
} int main()
{ return ;
}
以C++方式编译:通过~!没有问题! 以前C中是完全不能够的,因为函数名重复了。
改成C方式编译:
#include <stdio.h> void MyCout(int num)
{
printf("%d", num);
} void MyCout(char c)
{
printf("%c",c);
} void MyCout(float f)
{
printf("%f",f);
} void MyCout(char *str)
{
printf("%s", str);
} int main()
{ return ;
}
编译:
1>------ 已启动生成: 项目: OverloadeDemo, 配置: Debug Win32 ------
1> main.c
1>e:\c_code\overloadedemo\overloadedemo\main.c(9): error C2084: 函数“void MyCout(int)”已有主体
1> e:\c_code\overloadedemo\overloadedemo\main.c(3): note: 参见“MyCout”的前一个定义
========== 生成: 成功 0 个,失败 1 个,最新 0 个,跳过 0 个 ==========
改回C++模式,编译就通过,这个例子引入C++的一个机制:重载
重载——允许函数名相同,但后面的参数一定是不同的。如果函数名相同,参数也相同,就不能构成重载:
#include <cstdio> void MyCout(int num)
{
printf("%d", num);
} void MyCout(int num)
{
printf("%d", num);
} void MyCout(char c)
{
printf("%c",c);
} void MyCout(float f)
{
printf("%f",f);
} void MyCout(char *str)
{
printf("%s", str);
} int main()
{ return ;
}
编译:
1>------ 已启动生成: 项目: OverloadeDemo, 配置: Debug Win32 ------
1> main.cpp
1>e:\c_code\overloadedemo\overloadedemo\main.cpp(9): error C2084: 函数“void MyCout(int)”已有主体
1> e:\c_code\overloadedemo\overloadedemo\main.cpp(3): note: 参见“MyCout”的前一个定义
========== 生成: 成功 0 个,失败 1 个,最新 0 个,跳过 0 个 ==========
讲了半天,重载会有什么好处?
#include <cstdio> void MyCout(int num)
{
printf("%d", num);
} void MyCout(char c)
{
printf("%c",c);
} void MyCout(float f)
{
printf("%f",f);
} void MyCout(char *str)
{
printf("%s", str);
} int main()
{
int num = ;
char c = 'a';
char *str = "I Love Mark";
float f = 1.0002;
MyCout(f);
MyCout(str);
MyCout(num); return ;
}
下断点,运行:
1.000200I Love Mark100
看下C++中cout里面运算符的重载:
再看重载的具体原理,它具体的原理是什么;它里面有些什么潜规则呢?
下个断点,看看重载函数调用的顺序:
看跳转到哪:
其实本质上,C++最终还是生成了4个函数,表面上函数名一样,其本内里是不一样的4个函数。在调用这个函数的时候,编译器会帮我们选择一一对应的函数。根据函数的参数去匹配。
用反汇编查看调用匹配:
充分说明了,内里是不同的,不是表面上看到的一样的。
为什么编译器能给我们一一对应匹配呢?
因为编译器根据符号表里函数名,参数类型,域空间,等元素的不同来重定向函数名:
我们可以假设内里重载的函数名会改名:函数名@类型@类@命名空间……比如:?GetArryLens@MyString@@QAEIXZ
c++里面增加针对函数重载的“命名重定向”与“命名粉碎”的说法:你实际存在符号表里的函数名,被加了参数类型等附加名。这里就有一个问题:
名称被重定向了,命名粉碎了,内里名称已经被更改了,这时当别人调用这个函数的时候,名称已经不是这个我们命名名称了,这里如果别人想要你真实的函数名,会很困扰,这时应该怎么办?这个时候可以加一个前缀extern c :可以使用extern"c"(c编译模式)阻止命名粉碎。
在C中,没有命名粉碎这一概念的。
上面重载都讲参数类型的不同,同名函数重载,那如果这个函数的返回值不同,会不会影响重载失败呢?
重载与否跟返回值没关系,只与函数名和参数有关系:
看测试代码 :
#include <cstdio> void MyCout(int num)
{
printf("%d\n", num);
} void MyCout(char c)
{
printf("%c\n",c);
} void MyCout(float f)
{
printf("%f\n",f);
}
//MyCout@char* //假设按命名重定向,命名为MyCout@char*
void MyCout(char *str)
{
printf("%s\n", str);
}
//MyCout@char* //这里也是一样,生成和上面同名了。
int MyCout(char *str)
{
printf("%s\n", str);
return ;
} int main()
{
int num = ;
char c = 'a';
char *str = "I Love Mark";
float f = 1.0002;
MyCout(f);
MyCout(str);
MyCout(num); return ;
}
编译:报错!
1>------ 已启动生成: 项目: OverloadeDemo, 配置: Debug Win32 ------
1> main.cpp
1>e:\c_code\overloadedemo\overloadedemo\main.cpp(24): error C2556: “int MyCout(char *)”: 重载函数与“void MyCout(char *)”只是在返回类型上不同
1> e:\c_code\overloadedemo\overloadedemo\main.cpp(18): note: 参见“MyCout”的声明
1>e:\c_code\overloadedemo\overloadedemo\main.cpp(23): error C2371: “MyCout”: 重定义;不同的基类型
1> e:\c_code\overloadedemo\overloadedemo\main.cpp(18): note: 参见“MyCout”的声明
1>e:\c_code\overloadedemo\overloadedemo\main.cpp(34): warning C4305: “初始化”: 从“double”到“float”截断
1>e:\c_code\overloadedemo\overloadedemo\main.cpp(36): error C2264: “MyCout”: 函数定义或声明中有错误;未调用函数
========== 生成: 成功 0 个,失败 1 个,最新 0 个,跳过 0 个 ==========
命名重定向时,不考虑返回值,关键是参数的类型,参数的多少。重定向没有重名就能重载。
#include <cstdio> void MyCout(int num)
{
printf("%d\n", num);
} void MyCout(char c)
{
printf("%c\n",c);
} void MyCout(float f)
{
printf("%f\n",f);
}
//MyCout@char*
void MyCout(char *str)
{
printf("%s\n", str);
}
//MyCout@char*@int
int MyCout(char *str,int num)
{
printf("%s\n", str);
return ;
} int main()
{
int num = ;
char c = 'a';
char *str = "I Love Mark";
float f = 1.0002;
MyCout(f);
MyCout(str);
MyCout(num); return ;
}
编译通过。
只要最终命名粉碎后,没有重命名,则能构成重载。
PoEdu - C++阶段班- Lesson02_C to C++的更多相关文章
- PoEdu - C++阶段班【Po学校】- Lesson03-4_构造函数&赋值函数&拷贝构造函数&学习方式 - 第6天
PoEdu - C++阶段班[Po学校]- 第6天 课堂选择题目: 1 关于转换构造函数 ClassDemo demo = 1; 调用转换构造函数 2 关于拷贝赋值函数 demo =2; 首 ...
- PoEdu - C++阶段班【Po学校】- Lesson02_类与对象_第4天
复习:上节作业讲解 注意点: 设计SetString()的时候,要注意重置原来的空间. char * SetString(const char *str) { _len = strlen(str); ...
- PoEdu - C++阶段班【Po学校】- 第3天
引用 C中指针的功能强大,使用起来繁杂,因为指针要控制的东西太多:有指针的类型,指针的解引用,指针空间内的值,它本身是有空间的,有自己的地址等.指针也是强大的,比如:我们要在函数之内,修改方法之外的值 ...
- PoEdu - C++阶段班- Lesson07 To Lesson10_C to C++
07 重载导致的二义性 问题:为什么一定要重载呢?重载能方便我们注重函数的功能,当参数类型不确定时,我们能很便捷的利用重载的机制达到目的. 重载注意点:二义性 看代码: #include <c ...
- PoEdu - C++阶段班【Po学校】- 第1课
1 C++开讲 C ++ 伟大的编程语言:能提高程序运行效率,节约更多的资源,"正确的使用C++,能够抑制全球变暖问题". 2 C++能力雷达图 通过 1效率 2灵活度 3 抽象 ...
- PoEdu- C++阶段班【Po学校】-Lesson03_构造函数精讲 - 第5天
复习构造函数:1 与类同名 2 没有返回值 3 自动生成 4 手动后,不会自动生成 5 不在特定的情况下,不会私有 新建 类 两种方法示范 其一:在vs中选择类 ...
- PoEduo - C++阶段班【Po学校】-Lesson03-5_运算符重载- 第7天
PoEduo - Lesson03-5_运算符重载- 第7天 复习前面的知识点 空类会自动生成哪些默认函数 6个默认函数 1 构造 2 析构 3 赋值 4 拷贝构造 5 oper ...
- [福大软工] Z班 团队Beta阶段成绩汇总
Beta敏捷冲刺得分 队伍名 1 2 3 4 5 总分 Dipper 10 10 10 10 10 50 SWSD 9 9 9 9 7 43 五成胜算 10 10 10 10 10 50 人月神教 0 ...
- 福州大学软件工程1816 | W班 团队Alpha阶段成绩汇总排名(第9、10次作业)
写在前面 汇总成绩排名链接 1.作业链接 第九次作业--项目Alpha冲刺(团队) 第十次作业--事后诸葛亮(团队) 2.评分准则 本次作业包括现场Alpha答辩评分(映射总分为100分)+博客分(总 ...
随机推荐
- RNG vs EDG | SKT vs KTB [20160826]
G1 RNG:丽桑卓,古拉加斯,强行开团流. EDG:崔斯特,普朗克,伊莉斯游走,全球支援流,小规模团战能以多打少. G2 RNG:塔莉垭,纳尔,烬. EDG:雷克塞,艾克,劫,冲击后排. G3 RN ...
- startssl
Validation Success You have successfully authenticated domain "xxx.com.cn".You will be abl ...
- [zhang] ViewController的生命周期分析和使用
iOS的SDK中提供很多原生ViewController,大大提高了我们的开发效率,下面是我的一些经验. 一.结构 按结构可以对iOS的所有ViewController分成两类:1.主要用于展示内容的 ...
- spring mvc定时任务的简单使用
版权声明:本文为楼主原创文章,未经楼主允许不得转载,如要转载请注明来源. 说起定时任务,开发的小伙伴们肯定不陌生了.有些事总是需要计算机去完成的,而不是傻傻的靠我们自己去.可是好多人对定时器总感觉很陌 ...
- 【T电商 3】Nginx的Http(图片)服务器配置+ftp上传使用说明
在前两篇博客中提到了搭建Nginx和Ftp服务器,在本篇博客,主要是介绍Nginx的配置文件的使用,怎样修改配置文件使其成为一个图片服务器. 一.Nginx图片服务器配置 <span style ...
- 浅谈js的键值对key和value
> 昨晚无意中看到类似下面结构的一段代码的取值问题,引起我的兴趣,花了点时间写了个demo给大家分享一下... var obj = [ {"2011":{"name ...
- JS settimeout 使用笔记
无参数使用方法: setTimeout(function_name,delay_time); 基本使用方法是逗号前是函数名字,不能带有 xxxx(),不然不执行: 但是很多函数都要带参数的,以下是解决 ...
- Entity Framwork(EF) 7——在现在数据库的甚而上开发MVC 新项目
一.开发背景: 由于老系统已经无法满足实际业务需求,需在现有数据库的甚而上开发新的项目. 二.困难点: 而EF默认情况下是要删除现有数据库表格后重新创建,这是不允许的.当你创建数据库对象时系统会提示“ ...
- 动态规划 - 最长递增子序列(LIS)
最长递增子序列是动态规划中经典的问题,详细如下: 在一个已知的序列{a1,a2,...,an}中,取出若干数组组成新的序列{ai1,ai2,...,aim},其中下标i1,i2,...,im保持递增, ...
- Python之路【第十七篇】:Django【进阶篇 】
Python之路[第十七篇]:Django[进阶篇 ] Model 到目前为止,当我们的程序涉及到数据库相关操作时,我们一般都会这么搞: 创建数据库,设计表结构和字段 使用 MySQLdb 来连接 ...