C到C++II

2020-05-11 17:49:38 浏览数 (1)

C到C II

目录

结构,联合,枚举C 结构体C 联合C 枚举bool类型内联重载缺省参数和哑元哑元引用引用特点引用做参数引用做函数返回值

结构,联合,枚举

C 结构体

声明或定义结构体变量时可以省略struct,内部可以定义函数

代码语言:javascript复制
#include<iostream>
struct STU{
    int m_age;
    char m_name[20];
    void introduce(){
        std::cout << "我叫" << m_name << ",今年" << m_age << "岁" << std::endl;
    }
};

int main(){
    //C必须加上struct关键字才能定义变量,除非给结构体取别名
    STU stu = { 18,"小明" };
    stu.introduce();    //调用结构体里面的函数
    return 0;
}
C 联合

声明或定义联合变量,可以省略union 支持匿名联合

代码语言:javascript复制
//匿名联合示例    匿名联合不能作为全局,只能放在函数里面
#include<iostream>
int main(){
    union{
        char c;
        int i;
    };
    i = 65;
    std::cout << c << std::endl;
    return 0;
}
//打印结果
A
C 枚举

声明或定义枚举变量,可以省略enum 独立类型和整型不能隐式相互转换

代码语言:javascript复制
//枚举类型检查更为严格
enum Color{
    RED, 
    GREEN,
    BLUE
};
int main(){
    Color color;
    //在C中枚举类型可以隐式转换成整型
    //color = 1;    //不允许 会报错不能将 "int" 类型的值分配到 "Color" 类型的实体
    color = RED;    //类型检查更为严格
    return 0;
}

详细的结构体----C语言之结构体

bool类型

true 表示真 即单字节整数1 false 表示假 即单子接整数0

任何基本类型都可以隐式转换为布尔类型,遵循原则:非0即真,0即假

代码语言:javascript复制
#include<iostream>
//using namespace std;
int main(){
    bool flag = false;
    std::cout << flag << std::endl;
    flag = true;
    std::cout << flag << std::endl;
    //boolalpha     打印true/false    命名空间std里面的函数
    //noboolalpha   bool 打印字面值 0/1
    std::cout << std::boolalpha << flag << std::endl;
    std::cout << std::noboolalpha << flag << std::endl;
    return 0;
}
//打印结果
0
1
true
1

内联

用函数已被编译好的二进制代码,替换对该函数的调用指令。提高效率,避免函数调用开销

使用inline关键字期望该函数被优化为内联,是否内联由编译器决定,看你系统的心情决定是否优化。

内联会使可执行文件内存变大,只有频繁调用的简单函数适合内联。复杂函数和递归函数都不适合内联。

代码语言:javascript复制
//内联形式:函数前面加上inline关键字
inline int max(int a,int b){
    return a > b ? a : b;
}

重载

同一作用域中,函数名相同,参数表不同的函数,构成重载

代码语言:javascript复制
#include<iostream>
using namespace std;
//原函数
void foo(int a)   {
    cout << "foo(int)" << endl;
}
//重载函数1 参数类型不同
void foo(char a)  {
    cout << "foo(char)" << endl;
}
//重载函数2 参数数量不同 
void foo(int a, double b)  {
    cout << "foo(int,double)" << endl;
}
//重载函数3 参数顺序不同
void foo(double a, int b)  {
    cout << "foo(double,int)" << endl;
}
//不构成重载 重载与返回类型无关
//int foo(double a, int b){
//    cout << "foo(double,int)" << endl;
//}
int main(){
    foo(1);
    foo('a');
    foo(1, 1.314);
    foo(1.314, 1);
    return 0;
}
//打印结果
foo(int)
foo(char)
foo(int,double)
foo(double,int)

重载是通过C 编译器 函数改名实现的

怎么证明!在linux下 用gcc -c 获取.o文件 使用nm .o文件 查看

代码语言:javascript复制
//main.cpp文件
void fun(){}
void fun(int a,int b){}
void fun(char a,char b){}

我的Linux不知道装什么东西挂了,就用windows下的PowerShell演示一下

开始菜单下W开头找到Windows PowerShell,输入下面命令(好像要配置gcc,可以在Linux下试验)

代码语言:javascript复制
Windows PowerShell
版权所有 (C) Microsoft Corporation。保留所有权利。

PS D:测试> dir


    目录: D:测试


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----        2020/1/27     20:20             64 main.cpp


PS D:测试> g   -c .main.cpp
PS D:测试> dir


    目录: D:测试


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----        2020/1/27     20:20             64 main.cpp
-a----        2020/1/30      0:14            852 main.o


PS D:测试> nm .main.o
0000000000000000 b .bss
0000000000000000 d .data
0000000000000000 p .pdata
0000000000000000 r .rdata$zzz
0000000000000000 t .text
0000000000000000 r .xdata
000000000000000f T _Z3funcc
0000000000000002 T _Z3funii
0000000000000000 T _Z3funv
PS D:测试>

前面的不用看,看最后三行

代码语言:javascript复制
000000000000000f T _Z3funcc
0000000000000002 T _Z3funii
0000000000000000 T _Z3funv
前面一串数字代表地址 T代表函数 _Z代表标志符 
3代表函数名字长度(fun) cc代表两个char
ii代表两个int v代表void

缺省参数和哑元

为函数指定缺省值,调用时若未指定实参,则对应的形参取缺省值

  • 缺省参数只能在最后,即你某个参数指定为缺省参数,后面所有参数都要有缺省值
  • 最好在函数声明中指定缺省参数,这样可以利用声明改缺省值。
代码语言:javascript复制
#include<iostream>
using namespace std;
void fun(int a = 10, int b = 20);
int main(){
    fun();
    //利用声明改缺省值
    void fun(int a = 2, int b = 5);
    fun();
    return 0;
}
void fun(int a /*=10*/, int b /*= 20*/){
    cout << a << "," << b << endl;
}
//打印结果
10,20
2,5

哑元

只指定类型而不指定名称的函数参数,叫做哑元

代码语言:javascript复制
#include<iostream>
using namespace std;
void fun(int, int){
    cout << "哑元 占着茅坑不拉屎" << endl;
}
int main(){
    fun(1,2);
    return 0;
}

哑元有什么用呢!

  • 兼容之前版本
  • 形成函数重载

引用

引用是c 对c语言的重要扩充。引用就是某一变量(内存)的一个别名,对引用的操作与对变量直接操作完全一样。 格式:类型 &引用变量名 = 已定义过的变量名

引用特点
  • 引用就是变量的别名,一个变量可取多个别名
  • 引用必须初始化,不能为空
  • 引用只能在初始化的时候引用一次 ,不能更改为转而引用其他变量
代码语言:javascript复制
#include<iostream>
using namespace std;
int main(){
    int num = 10,temp = 20;
    //int &NUM = NULL;      //引用必须初始化,不能为空
    int &NUM = num; //此时对NUM的操作就是对num操作
    NUM = 100;
    cout << num << endl;
    //引用不能更换目标
    NUM=temp;    //此时不是改引用对象,而是赋值

    //引用变量和被引用的变量虽然是同一个变量,但是可以被不同修饰符修饰
    const int& const_num = num;
    //const_num = 20;   //不允许 错误:表达式必须为可修改的左值
    num = 20;
    cout << const_num << endl;
    return 0;
}

注意:被const修饰的变量被引用时必须被const修饰

代码语言:javascript复制
    const int a = 10;
    const int& A = a;
引用做参数

节省空间 提高效率

在函数中,形参的值可以由

值传递

形参生成局部临时变量接收实参的值

引用传递

形参是实参的别名

指针传递

传入实参的地址,指针通过地址访问修改值

代码语言:javascript复制
#include<iostream>
using namespace std;
//值传递
void fun1(int a){
    a  ;
}
//指针传递
void fun2(int* pa){
    (*pa)  ;
}
//引用传递
void fun3(int& ra){
    ra  ;
}
int main(){
    int a = 10, b = 10, c = 10;
    fun1(a);
    cout << a << endl;
    fun2(&b);
    cout << b << endl;
    fun3(c);
    cout << c << endl;
    return 0;
}
//打印结果
10
11
11

引用的本质就是指针 用来代替指针,弱化版指针,没有指针灵活,安全性更高

引用做函数返回值
代码语言:javascript复制
#include<iostream>
using namespace std;
//返回的是a的值
int fun1(int& a){
    return   a;
}
//返回值做引用 返回是a的别名
int& fun2(int& a){
    return   a;
}
int main(){
    int num = 10;
    //fun1(num) = 100;  //fun1返回的是一个值
    fun2(num) = 100;    //fun2返回的是一个变量
    cout << num << endl;
    return 0;
}

0 人点赞