【C++】复习1(函数符号生成规则、内联函数、C/C++相互调用、const 、引用)

目录

一、函数的默认值

二、函数符号生成规则

三、函数重载

 四、内联函数

五、C/C++的相互调用

六、引用

七、const


一、函数的默认值

    1、自右向左依次赋值(原因:与匹配 顺序有关,参数匹配是从左向右);

    2、不能重复赋值;

    3、一般给在声明上。

二、函数符号生成规则

    1、C函数符号生成规则:

                   与函数名有关  

                _cdel调用约定(C标准调用约定):函数名前加下划线。(调用方开辟,调用方清理)

                _stdcall调用约定:函数名前加下划线,函数名后加“@”符号和其参数字节。(调用方开辟,被调用方清理)

                _fastcall调用约定:函数名前加“@”符号,函数名后加“@”字符和其参数字节。

    2、C++函数符号生成规则:

                  函数原型有关:

                      1)函数返回值(不能作为重载的依据);

                      2)函数名称(不能作为重载的依据);

                      3)函数形参(类型、个数、顺序)。

                 _cdecl调用约定:“?”+函数名+参数表的开始标识 “@@YA” + 函数返回类型代号+参数类型代号 +结束标识“@Z”或“Z”(无参数)。

                 _stdcall调用约定:“?”+函数名+参数表的开始标识“@@YG”+函数返回类型代号+参数类型代号 +结束标识“@Z”或“Z”(无参数)。

                 _fastcal调用约定:“?”+函数名+参数表的开始标识 “@@YI”+ 函数返回类型代号+参数类型代号 +结束标识“@Z”或“Z”(无参数)。
 

int Max(int a, int b)//?Max@@YAHHH@Z
{
	return a > b ? a : b;
}
double Max(double a, double b)//?Max@@YANNN@Z
{
	return a > b ? a : b;
}
char Max(char a, char b)
{
	return a > b ? a : b;
}
int main()
{
 
	int max = Max(10, 20);
	char max = Max('a', 'b');
    double max = Max(0.23,0.21);
	return 0;
}

三、函数重载

          同名函数的关系

函数重载的三要素:

           1)同名;

           2)形参不同(①形参类型不同、②形参个数不同、③形参顺序不同)

           3)同作用域

  注意:同函数名、同参数列表、返回值不同的函数重载 和 有默认实参函数的重载 不能构成函数重载。编译器只使用形参列表来区分重载的函数,所以同函数名,同参数列表,返回值不同的函数重载 和 有默认实参函数的重载,编译无法区分,然后报错。

 四、内联函数

将规模小,而使用频繁的函数声明为内联函数。

1、定义:

inline函数:在编译时将所调用函数的代码直接嵌入到主调函数中,而不是将流程转出去。

    指:当编译器发现某段代码在调用一个内联函数时,它不是去调用该函数,而是将该函数的代码,整段插入到当前位置。这样做的好处是省去了调用的过程,加快程序运行速度。这样做的不好处:由于每当代码调用到内联函数,就需要在调用处直接插入一段该函数的代码,所以程序的体积将增大。内联函数并不是必须的,它只是为了提高速度而进行的一种修饰。要修饰一个函数为内联型,使用如下格式: 
inline 函数的声明或定义 
简单一句话,在函数声明或定义前加一个 inline 修饰符。 
inline int max(int a, int b) 

   return (a>b)? a : b; 
}

简而言之就是:把代码在函数的调用点直接展开以空间换时间

2、注意事项:

        1)写在头文件下;在一个文件中定义的内联函数不能在另一个文件中使用。它们通常放在头文件中共享。

        2)只在release版本生效;

        3)是给编译器的一个建议(由编译器决定);

        4)加在声明点一定无效(inline是基于实现的,不是基于声明的)内联函数要在函数被调用之前声明。关键字inline 必须与函数定义体放在一起才能使函数成为内联,仅将inline 放在函数声明前面不起任何作用。

        5)一定不能设置成inline 的有(递归、循环、switch),否则,函数定义时即使有inline关键字,编译器也会把该函数作为非内联函数处理。 

3、inline函数和宏的区别    (内联是一种更安全的宏)

        inline函数是在编译阶段展开;有类型检查和安全检查

        宏是在预编译阶段展开代码,不需要额外的空间和时间方面的开销。无类型检查和安全检查。

宏的不足:
     1)宏不能访问对象的私有成员。
     2)宏的定义很容易产生二意性。

内联函数和宏的区别在于,宏是由预处理器对宏进行替代,而内联函数是通过编译器控制来实现的。而且内联函数是真正的函数,只是在需要用到的时候,内联函数像宏一样的展开,所以取消了函数的参数压栈,减少了调用的开销。可以向调用函数一样来调用内联函数,而不必担心会产生于处理宏的一些问题。

当执行开销  小于  调用开销(开栈开销)     建议用inline

执行开销   大于   调用开销                不建议用inline

五、C/C++的相互调用

       C 编译器编译函数时不带参数的类型信息,只包含函数的符号名字。如 void foo( int x ) , C 编译器会将此函数编译成类似 _foo 的符号,C 链接器只要找到了调用函数的符号,就会认为链接成功。而 C++ 编译器为了实现函数重载,会在编译时带上函数的参数信息。如它可以把上面的函数编译成类似于 _foo_int 这样的符号。

在C/C++相互调用时用   extern"C "声明  把包含的代码以C的规则进行处理。

1、C++调用C

    在.cpp文件加上extern"C"

/* cfile.c */

#include <stdio.h>

void C_Func()
{
    puts("Hello, I'm C_Func");  
}

 

/* cppfile.cpp */

#include <iostream>

extern "C" void C_Func(void);

int main()
{
    C_Func();
    return 0;
}

2、C调用C++

    1)C++源文件可以修改   在.cpp加extern“C”(整个函数)

    2)C++源文件不可修改  加中间层

/* cppfile.cpp */

#include <iostream>
#include "cpphfile.h"

using namespace std;

void Myclass::print()
{
    cout << "Hello, I'm print function." << endl;
}
/* cpphfile.h */

#ifndef _CPPCLASS_H__
#define _CPPCLASS_H__

class Myclass{
public:
    void print();
};

#endif
/* wrapper.cpp 这个文件实现调用 C++ 的接口*/

#include "cpphfile.h"

extern "C" {

    struct wrapper_class{
        Myclass w_class;
    };

    struct wrapper_class* get_object()
    {
        return new struct wrapper_class;
    }

    void call_cpp_print(struct wrapper_class* p)
    {
        p->w_class.print();
    }

}
/* cfile.c */

#include <stdio.h>

struct wrapper_class *test;

int main()
{
    /* 创建对象 */
    test = get_object();

    /* 调用 C++ 函数 */
    call_cpp_print(test);
    
    system("pause");
}

 

    .c被调用  用 #ifdef_cplasplas

 

六、引用

符号:&  别名

#include<iostream>
using namespace std;
int main(){
    double a=10.3;
    int &b=a; //错误,引用的类型必须和其所绑定的变量的类型相同
    cout<<b<<endl;
}

引用的特点:

    1)引用一定要初始化(要先有内存单元再起别名)

              底层使用指针支持,在所有引用变量使用的地方,系统自带解引用。

    2)引用不能引用不能取地址的数据(只能引用能取地址的数据)

    3)引用不能改变(别名一旦赋予,便不能改变)

    4)引用变量使用时使用的是引用变量(别名)所引用的 变量

    5)引用不是定义一个新的变量或对象,因此内存不会为引用开辟新的空间存储这个引用

#include<iostream>
using namespace std;
int main(){
    int value=10;
    int &new_value=value;
    cout<<"value在内存中的地址为:"<<&value<<endl;
    cout<<"new_value在内存中的地址为:"<<&new_value<<endl;
    return 0;
}

//value  地址:0x6ffe44
//new_value  地址: 0x6ffe44

 常引用  引用  不能取地址的数据   数据生成一个临时量,取临时量的地址,常引用引用临时量。

引用作为函数的返回值

引用作为函数的返回值时,必须在定义函数时在函数名前加&

七、const

C++  const修饰的属性为local属性

在C语言中:const修饰的是常变量  在编译阶段   常变量是否被做左值,其他处理与变量一样。

在C++中 :是常量    在编译阶段      把用到常量的地方替换成常量初始化的值。

语法:const 类型 &引用名=目标变量名;

常引用不允许通过该引用对其所绑定的变量或对象进行修改

#include<iostream>
using namespace std;
int main(){
    int a=10;
    const int &new_a=a;
    new_a=11;//错误!不允许通过常引用对其所绑定的变量或对象进行修改 
    return 0;
}
#include<iostream>
#include<string> 
using namespace std;
string func1(){
    string temp="This is func1";
    return temp;
}
void func2(string &str)//改为 void func2(const string &str)
{
    cout<<str<<endl;
}
int main(){
    func2(func1());
    func2("Tomwenxing");
    return 0;
}
//程序报错:这是由于func1()和“Tomwenxing”都会在系统中产生一个临时对象(string对象)来存储它们,而在C++中所有的临时对象都是const类型的,而上面的程序试图将const对象赋值给非const对象,这必然会使程序报错。如果在函数func2的参数前添加const,则程序便可正常运行了

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值