14_C++对c的扩展
c++对c的扩展
1 作用域运算符(重要)
符号
::
作用:
1,当局部变量与全局变量重名时,区分局部变量与全局变量 变量名 局部变量 ::变量名 全局变量 2,指明使用的变量所属的命名空间 命名空间名::变量名 3,实现函数的声明与定义分离 如: namespace E { void method02();//函数的声明 } void E::method02()//函数的定义(实现) { }
如:C中代码
#include <stdio.h> int num = 10; int main(int argc, char const *argv[]) { int num = 20; printf("局部变量num = %d\n", num); // 在c语言中当局部变量与全局变量重名时,因为就近原则,默认使用的是局部变量 // 此时无法使用全局变量 return 0; }
如:c++代码
#include <iostream> using namespace std; int num = 10; int main(int argc, char const *argv[]) { int num = 20; cout << "局部变量 num = " << num << endl; cout << "全局变量 num = " << ::num << endl; return 0; }
2 namespace与using(重要)
namespace
含义
命名空间
语法
namespace 空间名 { //变量 //函数 }
注意
1,命名空间只能全局范围内定义(必须定义在函数外) 2,命名空间可嵌套命名空间 3,命名空间是开放的,即可以随时把新的成员加入已有的命名空间中 4,声明和实现可分离 5,无名命名空间,意味着命名空间中的标识符只能在本文件内访问 6,命名空间别名
示例1
#include <iostream> using namespace std; namespace A { int a = 1; int b = 11; char c = 'A'; } namespace B { int a = 2; int b = 22; char c = 'B'; } // 命名空间可以嵌套 namespace C { int a = 4; namespace D { int a = 5; } } // 命名空间是开放的,即可以随时把新的成员加入已有的命名空间中 // 不能在次定义相同的变量 namespace A { int d = 111; } namespace E { // 命名空间中可以定义函数 void method01() { cout << "method01" << endl; } // 声明和实现可分离 void method02(); } void E::method02() { cout << "method02" << endl; } // 无名命名空间 namespace { int a = 6; } int main(int argc, char const *argv[]) { int a = 3; cout << "A a = " << A::a << endl; cout << "B a = " << B::a << endl; cout << "a = " << a << endl; cout << "C a = " << C::a << endl; cout << "D a = " << C::D::a << endl; cout << "A d = " << A::d << endl; cout << "无名 a = " << ::a << endl; E::method01(); E::method02(); return 0; }
示例2
#include <iostream> using namespace std; namespace A { int a = 1; } int main(int argc, char const *argv[]) { // 命名空间别名 namespace A1 = A; cout << "A a = " << A::a << endl; cout << "A1 a = " << A1::a << endl; return 0; }
using
作用:
声明可使得指定的标识符可用
语法:
1,声明命名空间中单个变量 using 命名空间名::变量名; 2,声明命名空间中单个函数 using 命名空间名::函数名; 3,声明整个命名空间 using namespace 命名空间名;
示例:
#include <iostream> using namespace std; int main() { int i = 10; char c = 'A'; void methodA() { cout<<"methodA"<<endl; } } //声明命名空间中的单个变量 //声明后在使用该变量就可以直接使用 using A::i; //声明命名空间中的单个函数 //声明后在使用该函数就可以直接使用 using A::methodA; //声明整个命名空间 //声明后整个命名空间中所以内容都可直接使用 using namespace A; int main(int argc, char const *argv[]) { cout << "A i = " << A::i << endl; cout << "A i = " << i << endl; methodA(); cout << "A c = " << c << endl; return 0; }
注意:
> using遇到函数重载,using 声明就声明了这个重载函数的所有集合。 >重载: 同一片空间中,函数名相同,形参列表不同,成为重载 c语言不支持重载 c++支持重载 使用 using 声明或 using 编译指令会增加命名冲突的可能性。
3 全局变量检测增强
如c:
#include <stdio.h>
int a; // c语言编译器会认为此处为变量的声明
int a;
int a = 10; // 变量的定义与初始化
int main(int argc, char const *argv[])
{
return 0;
}
如:c++
#include <iostream>
using namespace std;
int a; // c++编译器将此处理解为变量的定义
// int a = 10;//此时将会重复定义,程序无法编译通过
int main(int argc, char const *argv[])
{
return 0;
}
3.1 C++中所有变量和函数都必须有类型
如:c
#include <stdio.h> void fun(i) { printf("fun\n"); } void fun02() { printf("fun02\n"); } int main(int argc, char const *argv[]) { fun(10); fun02(); return 0; }
如:c++
#include <iostream> using namespace std; // c++中变量必须有类型,此时i没有类型所有无法编译通过 // void fun(i) // { // } // 形参中的void表示没有形参列表 void fun02(void) { cout << "fun02\n"; } int main(int argc, char const *argv[]) { fun02(); return 0; }
3.2 更严格的类型转换
如:c编译通过
#include <stdio.h> #include <stdlib.h> int main(int argc, char const *argv[]) { int *nums = calloc(10, sizeof(int)); return 0; }
c++,必须强转后才可通过
#include <iostream> #include <stdlib.h> using namespace std; int main(int argc, char const *argv[]) { int *nums = (int *)calloc(10, sizeof(int)); return 0; }
3.3 struct类型加强(掌握)
c 中定义结构体变量需要加上 struct 关键字,c++不需要。
c 中的结构体只能定义成员变量,不能定义成员函数。c++即可以定义成员变量,也可以定义成员函数
示例:
#include <iostream> using namespace std; struct Person { char name[50]; int age; void eat() { cout << name << "吃面条" << endl; } void game(); }; void Person::game() { cout << name << "玩游戏" << endl; } int main(int argc, char const *argv[]) { // c语法 struct Person p1 = {"tom", 18}; // c++语法,定义结构体变量时可以不用写struct关键字 Person p2 = {"jek", 18}; p1.eat(); p2.eat(); p1.game(); return 0; }
3.4 新增bool类型
关键字
bool 数据类型 true 真 false 假
true(转换为整数 1)和 false(转换为整数 0) bool类型的变量取值:true或false bool 类型赋值时,非 0 值会自动转换为 true(1),0 值会自动转换 false(0)
注意
c 语言中也有 bool 类型,在 c99 标准之前是没有 bool 关键字,c99 标准已经有 bool 类型,包含头文件 stdbool.h,就可以使用和 c++一样的 bool 类型。
示例
#include <iostream> using namespace std; int main(int argc, char const *argv[]) { cout << true + 0 << endl; cout << false + 0 << endl; bool tag = true; tag = false; tag = 10; cout << tag << endl; return 0; }
3.5 三目运算符功能增强
# c语言三目运算符返回的是值
#c++三目运算符返回的是变量
如c
#include <stdio.h> int main(int argc, char const *argv[]) { int a = 10; int b = 1; // c语言中三目返回的是值,不是变量 int c = a > b ? a : b; // 所以三目在c中不能作为左值,无法通过编译 (a > b ? a : b) = 100; return 0; }
如:c++
#include <iostream> using namespace std; int main(int argc, char const *argv[]) { int a = 10; int b = 1; // c++中三目返回的是变量,不是值 int c = a > b ? a : b; // 所以三目在c++中可以作为左值 (a > b ? a : b) = 100; cout << "a = " << a << endl; return 0; }
4 C/C++中的const
全局变量
c
#include <stdio.h> const int num = 10; int main(int argc, char const *argv[]) { // const修饰的变量不能重新赋值 // num = 1; // 无法进行修改,因为num的值存储在常量区 int *p = # *p = 1; printf("num = %d\n", num); printf("*p = %d\n", *p); return 0; } // 出现段错误
c++
#include <iostream> using namespace std; const int num = 10; int main(int argc, char const *argv[]) { // num = 1; int *p = (int *)# *p = 1; cout << "num = " << num << endl; cout << "*p = " << *p << endl; return 0; } // 出现段错误
#include <iostream> using namespace std; struct Person { int age; }; const Person p = {2}; int main(int argc, char const *argv[]) { Person *p1 = (Person *)&p; p1->age = 10; cout << "p.age = " << p.age << endl; return 0; }
局部变量
c
#include <stdio.h> int main(int argc, char const *argv[]) { const int num = 10; // const修饰的变量不能重新赋值 // num = 1; // 可以进行修改,因为num的值存储在栈区 int *p = # *p = 1; // 修改完成后num的值也将被修改 printf("num = %d\n", num); printf("*p = %d\n", *p); return 0; }
c++
#include <iostream> using namespace std; int main(int argc, char const *argv[]) { // 在c++中const修饰的变量会存储在常量表中 const int num = 10; // num = 1; // 当我们对常量表的中的变量区地址时,系统会开辟一片内存,使其存储其变量的值 int *p = (int *)# // 此时使用指针对其修改,修改的是新开辟的内存中的值 *p = 1; // 此时num的值依旧从常量表中获取,值并没有发生改变 cout << "num = " << num << endl; cout << "*p = " << *p << endl; return 0; }
#include <iostream> using namespace std; int main(int argc, char const *argv[]) { int a = 10; // 在c++中const修饰的变量以其他变量初始化,会为其分配内存空间 const int num = a; // num = 1; int *p = (int *)# *p = 1; // 此时num的值依旧从常量表中获取,值发生改变 cout << "num = " << num << endl; cout << "*p = " << *p << endl; return 0; }
#include <iostream> using namespace std; struct Person { int age; }; int main(int argc, char const *argv[]) { const Person p = {2}; // const修饰自定义类型的变量,无法修改其自定义变量中的成员变量 // p.age = 10; // 无法获取其成员变量的地址 // int *p = &(p.age); // const修饰的自定义类型的变量,无法获取其地址,因为地址是使用const 数据类型 *修饰的 // 转换后就可以使用该指针修改其自定义类型中的成员变量 Person *p1 = (Person *)&p; p1->age = 10; cout << "p.age = " << p.age << endl; return 0; }
总结(背诵)
全局变量:c/c++没区别,会出段错误
局部变量:
1,如果const修饰的普通类型的变量,使用常量初始化
如:
const int a = 10;
此时会生成符号表,当获取其变量的地址时会开辟新的地址,使用获取的地址
修改其值,不会影响符号常量表中的数据
2,如果const修饰的普通类型的变量,使用变量初始化
如:
int y = 10;
const int x = y;
此时不会生成符号常量表,会直接开辟地址,存储该变量,获取的地址修改其值,会修改其内容.
int *p =(int *)&x;
*p = 1;
cout << x << endl; //1
cout << *p << endl; //1
3,如果const修饰的是自定义变量
1,无法直接修改其自定义类型中的成员变量
2,无法获取自定义类型中的成员变量的地址
3,获取其自定义类型变量的地址需强转,强制过会就可以使用该地址修改其成员变量的值
建议
尽量以 const 替换#define
const与#define的区别
1.const 有类型,可进行编译器类型安全检查。#define 无类型,不可进行类型
检查.
2.const 有作用域,而#define 不重视作用域,默认定义处到文件结尾.如果定义在指定作用域下有效的常量,那么#define 就不能用
5 引用【重要】
英文名:reference
符号: &
作用: 给已有变量起别名
语法:
基本数据类型 数据类型 &变量A = 变量B; 给变量B取别名叫变量A 此时操作A就是在操作B,操作B就是在操作A 数组类型 方式1: typedef 数组的数据类型 类型别名[数组长度]; 类型别名 &别名 = 数组名; 方式2:【*】 数组的数据类型 (&别名)[数组长度] = 数组名; 注意:此时数组长度不能忽略不写 指针 数据类型 *&别名 = 指针变量名; 常量 const 数据类型 &别名 = 变量名;
注意
1,不能返回局部变量的引用 2,函数当左值,必须返回引用。
本质
引用的本质在 c++内部实现是一个指针常量. Type& ref = val; // Type* const ref = &val;
如
#include <iostream> using namespace std; struct Stu { int age; }; // void test(Stu s) // { // s.age = 10; // } void test(Stu &s) { s.age = 10; } int main(int argc, char const *argv[]) { Stu stu = {1}; test(stu); cout << "stu.age = " << stu.age << endl; return 0; }
6 内联函数(了解)
语法
inline 返回值类型 函数名(形参列表) { 函数体 }
特点
内联函数:在编译阶段像宏一样展开。 作为类的成员函数,有作用域的限制 内联函数为了继承宏函数的效率,没有函数调用时开销,然后又可以像普通函数样, 可以进行参数,返回值类型的安全检查,又可以作为成员函数
注意:取决于编译器
1,inline只能在定义函数的时候修饰。 2,任何在类内部定义的函数自动成为内联函数。 3,inline修饰的函数是否为内联函数,取决于编译器。对于非inline修饰的函数,也有可能转成内联函数(体积小、功能简单的函数)。
条件
#不能存在任何形式的循环语句 #不能存在过多的条件判断语句 #函数体不能过于庞大 #不能对函数进行取址操作
宏函数和内联函数区别(重要)
宏函数(带参宏):
参数没有类型,不能保证参数的完整型。
宏函数 在预处理阶段展开。
宏函数 没有作用域限制 不能作为类的成员。
内联函数:
参数有类型 保证参数的完整型。
内联函数 在编译阶段 展开。
内联函数 有作用域限制 能作为类的成员
7 对函数的加强(重要)
形参默认值
语法
返回值类型 函数名(数据类型 变量名1 = 值,数据类型 变量名2 = 值,...) { 函数体 }
注意
形参中有默认值的参数,在函数调用时可传可不传,如果不传使用默认值 调用有默认值的函数,传入实参依据会按形参的顺序赋值 如果某个形参有默认值,其后的形参必须也有默认值
8 形参占位符
如:
void test(int a, int, int)
{
}
// 无论占位符在前还是后 中间也都行
void test(int, int a, int, int)
{
}
// 只有对应有形参的数 参与计算 占位符 只是占位置 没用
1,形参占位符可以有多个
2,可以在形参的任意位置
9 重载
函数名相同,形参列表不同,称为重载
多态的一种体现
原文地址:https://blog.csdn.net/weixin_51253120/article/details/141938341
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!