bool flag = true;
cout << flag << endl;
flag = false;
cout << flag << endl;
// 输出结果为1
//0
double a = 0.5;
double b = 0.25;
cout << a / b << endl;
// 结果是整数2
double a = 0.5;
double b = 0.22;
cout << a / b << endl;
//结果是小数
string names[3] = {"张三", "李四", "王五"};
cout << names[0] << endl;
//打印张三
(1)两个函数函数名相同, 但是参数的个数或者参数的类型不同.返回值不同, 不能构成函数重载.因为
double fun() {
return 0;
}
int fun() {
return 0;
}
int main() {
fun();// 有歧义, 不知道调用哪个函数.
}
(2)调用函数时, 实参的隐式类型转换可能会产生二义性.
#include
using namespace std;
void display(long a) {
cout << "long" << a << endl;
}
void display(double a) {
cout << "double" << a << endl;
}
int main()
{
display(10);// int类型
display(10L);// long类型
display(10.0);// double类型
return 0;
}
// 此时有问题, 因为int类型的10, 可以隐式类型转换为long和double类型, 产生二义性.
本质:采用了name mangling或者叫name decoration技术
函数重载的底层是编译器采取了name mangling技术, 就是C++编译器默认会根据参数对符号名(比如函数名)进行修饰,改编, 生成新的函数名, 这个新的函数名会包含参数的信息.所以其实调用时函数名其实是不同的可以通过IDA不用debug模式(会添加很多调试信息导致看不到),而release模式(不添加调试信息,但会被编译器做优化也会导致看不到)所以采用release模式禁止优化来看到, 所以这些函数名可以同时存在, 并且可以正常调用.
即:重载时会生成多个不同的函数名, 不同的编译器(MSVC(微软VS的编译器), g++)有不同的生成规则.
C++允许函数设置默认参数, 在调用时可以根据情况省略实参, 规则如下:
(1)默认参数只能按照右到左的顺序.
#include
using namespace std;
int func(int v1, int v2 = 3, int v3 = 5) {
return v1 + v2 + v3;
}
int func1(int v1 = 3, int v2 = 3, int v3 = 4) {
return v1 + v2 + v3;
}
/*
int func2(int v1 = 3, int v2) {
}
错误,默认参数必须从右到左*/
int main()
{
cout << func(1) << endl;
cout << func(1,2) << endl;
cout << func(1, 2, 3) << endl;
cout << func1() << endl;
return 0;
}
(2)如果函数同时有声明, 实现, 默认参数只能放在函数声明中.
(3)默认参数的值可以是常量, 全局符号(全局变量, 函数名)
例如:
#include
using namespace std;
int age = 20;
void sum(int v1 = 5, int v2 = age) {
cout << v1 + v2 << endl;
}
int main()
{
sum();
return 0;
}
#include
using namespace std;
void func(int v1, void(*p)(int)) {
p(v1);
}
void test(int a) {
cout << a << endl;
}
int main()
{
func(20, test);
return 0;
}
#include
using namespace std;
void test(int a) {
cout << a << endl;
}
void func(int v1, void(*p)(int) = test) { // 默认参数是函数名
p(v1);
}
int main()
{
func(20);
return 0;
}
(4)用途: 如果函数的实参经常是同一个值, 可以考虑使用默认参数
(5)函数重载, 默认参数可能会产生冲突, 二义性(建议优先选择默认参数)
#include
using namespace std;
void display(int a, int b = 20) {
cout << a << endl;
}
void display(int a) {
cout << a << endl;
}
int main()
{
display(10);
// 10既可以传给第一个也可以传给第二个, 产生二义性
return 0;
}
(6)默认参数的本质:
还是传两个参数, 只不过传的是默认参数的值, 和原来的没有不同, 只不过编译器帮我们做了一些事情而已.
(1)被extern “C” 修饰的代码会按照C语言的方式去编译
例如:
#include
using namespace std;
extern "C" void func() {
}
// 会产生错误
extern "C" void func(int v) {
}
int main()
{
return 0;
}
也可以
#include
using namespace std;
extern "C" {
void func() {
}
void func(int v) {
}
}
int main()
{
return 0;
}
(2)如果函数同时有声明和实现, 要让函数声明被extern “C” 修饰, 函数实现可以不修饰.
(1)第三方框架\库:可能是用C语言写的开源库
在C++里调用C语言函数时, 经常用到extern “C”
因为C语言和C++的编译规则不同, C语言没有name mangling技术来修饰函数名.
extern "C" {
#include "math.h"// 因为math.h是用C语言写的第三方库, 所以要加extern "C", 这样可以把第三方库的函数声明全拿过来, 在源文件里就可以调用函数了.
}
但如果把extern “C” 直接写在第三方库的头文件里更方便, 在别人用第三方库时, 不用extern "C"了.但是这样会导致另一个问题, 如果用在C语言代码里时, C语言没有extern "C"这个东西, 所以会报错, 所以要用下面的东西
C++环境下, 编译器会自动定义一个宏, __cplusplus
代表这是C++环境, 所以可以通过是否有这个宏来区分C++环境.例如:在math.h头文件中
#ifdef __cplusplus
extern "C" {
#endif
int sum(int v1, int v2);
int del(int v1, int v2);
int divide(int v1, int v2);
#ifdef __cplusplus
}
#endif
(2)补充:在自己编写的第三方库.c文件中, 一般也要包含自己写的.h头文件, 因为这个.c文件可能会存在函数之间互相调用, 而没有头文件, 就不能调用了.
(3)补充:在.h文件中, 为了防止重复包含头文件,在.h文件中这样写:
#ifndef ABC //举例
#define ABC
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
int sum(int v1, int v2);
int del(int v1, int v2);
int divide(int v1, int v2);
#ifdef __cplusplus
}
#endif // __cplusplus
#endif // !ABC
这样如果出现重复包含头文件时, 会因为已经定义过ABC导致后面的代码不会参与编译.防止头文件的内容被重复包含.
但是如果还有一个.h文件也瞎写成ABC, 就会导致错误
所以这个宏名是有规范的, 规定: 写成文件名就可以保证不同例如: __MATH_H
#ifndef __MATH_H
#define __MATH_H
因为这是特殊的宏所以要带下划线.
#pragma once 可以防止整个头文件的内容被重复包含
与#ifndef #define #endif 差不多
区别:
(1)较老的编译器不支持比如:gcc 3.4版本之前
(2)#ifndef #define #endif 受C\C++标准的支持, 不受编译器的任何限制.
(3)#ifndef #define #endif 可以针对一个文件中的部分代码, 而#pragma once 只能针对整个文件.
其他C++系列文章:
C++知识点总结(基础语法1-函数重载, 默认参数)
C++知识点总结(基础语法2-内联函数, const, 引用)
C++知识点总结(面向对象1-类和对象, this指针, 内存布局)
C++知识点总结(面向对象2-构造函数, 初始化列表)C++知识点总结(面向对象3-多态)
C++知识点总结(面向对象4-多继承, 静态成员static)
C++知识点总结(面向对象5-const成员, 拷贝构造函数)
C++知识点总结(面向对象6-隐式构造, 友元, 内部类, 局部类)
C++知识点总结(其他语法1-运算符重载)
C++知识点总结(其他语法2-模板, 类型转换, C++11新特性)