[C++ 面试基础知识总结]表达式和函数

简介: [C++ 面试基础知识总结]表达式和语句参考书籍:《C++ Primer》目录C 面试基础知识总结表达式和语句目录运算符优先级算数运算符运算对象转换商和余数逻辑运算符强制转换类型数组形参和返回不能返回局部函数的指针和引用重载函数预处理器变量函数指针运算符优先级算数运算符运算对象转换

[C++ 面试基础知识总结]表达式和语句

参考书籍:《C++ Primer》

目录

运算符优先级

这里写图片描述
这里写图片描述

算数运算符

运算对象转换

小整数类型(bool,char,short)进行运算时通常会提升成较大的整数类型int。

bool b = true;
bool b2 = -b;

最终得到b2值为true,原因在于bool值不能直接进行算数运算,需要转化成int,-b的结果是-1,不等于0,所以b2的值为真。

商和余数

C++11新标准则规定商一律向0取整,所以-(m)/n和m/(-n)都等于-(m/n),m%(-n)等于m%n,(-m)%n等价于-(m%n)。

-21/ -8 // 根据商向0取整的原则,结果为2
-21% -8 // 由于商为2,余数为(-21-(-8)*2)=-5

21/ -5 // 根据商向0取整的原则,结果为-4
21% -5 // 由于商为-4,余数为(21-(-5)*(-4))=1

逻辑运算符

&&和||都是短路求值,仅当左侧运算对象无法确定表示结果时才会计算右侧运算对象。

#include <iostream>

int _tmain(int argc, _TCHAR* argv[])
{
    auto i = 0;
    if (++i == 1 || ++i == 0)
    {
        cout << i << endl;
    }
    return 0;
}

输出结果为1,因为执行++i == 1后,已经可以判定整个表达式为真了,不用再去计算右侧运算对象了,++i == 0没有执行,所以只对i进行了一次递增操作。

强制转换类型

static_cast可以进行不包含底层const的类型转换,const_cast 只能改变运算对象的底层const。

const char *p;
static_cast<char*p>(p); // 错误,不能用static_cast转换掉const
const_cast<char*p>(p); // 正确,const_cast去掉了const属性
static_cast<string>(p); // 正确,字符串字面值转换成string类型
const_cast<string>(p); // 错误,const_cast只能改变常量属性

数组形参和返回

数组是无法拷贝的,所以我们为函数传递一个数组时,实际上传递的是指向数组首元素的指针。函数也不能返回数组,只能返回数组的指针或引用。

//以下两个函数是等价的
void print(const int*);
void print(const int[]);
//以下两个函数是等价的
void print(int (*a)[]);
void print(int a[][]);
// 返回一个有10个元素的整型数组的指针,函数有一个int类型的形参i
int (*func(int i))[10];
// C++11的尾置返回类型写法,与上述声明等价
auto func(int i) -> int(*)[10];
// C++11中可用decltype,需要注意decltype并不负责把数组转化成指针,需要在声明函数的时候加一个*
int a[10];
decltype(a) *func(int i);

不能返回局部函数的指针和引用

局部对象在函数完成后,它所占的的存储空间也随之被释放掉,因此,函数终止意味着局部变量的指针或引用将指向不再有效的内存区域。

const string &func(){
    string ret;
        if (!ret.empty())
        {
            return ret;
        }
        else
        {
            return "Empty";
        }   
}

两个返回都是错误的,试图返回局部变量或局部临时值的引用。

重载函数

重载函数名字和返回类型相同,但形参列表不同。顶层const不影响传入函数的对象,而底层const会。

int func(int*);
int func(double*); //正确重载函数,用于double型指针
void func(int*); //错误,只有返回类型不同
int func(const int*); //底层const,正确重载函数,用于常量整型指针
int func(int* const); //顶层const,重复声明

如果在内层作用域中声明名字,将会隐藏外层作用域的同名实体。在不同的作用域无法重载函数名。

string read();
void func(const string&);
void func(double):
int _tmain(int argc, _TCHAR* argv[])
{
    bool read = false;
    //错误,声明变量也会隐藏同名函数
    string s = read();
    void func(int);
    //错误,内层作用域中的的func函数隐藏了外层的func函数,现在的func只能接收int型参数。
    func("value");
    //不会报错,但是调用的是void func(int)
    func(3.14);
    return 0;
}

确定某次调用该选用哪个重载函数时会进行函数匹配,如果有且仅有一个函数匹配情况优于其它所有函数,则匹配成功,否则会因调用二义性而失败。
匹配优先级:
1.精确匹配:类型相同,数组类型或函数类型转化成对应的指针,顶层const
2.转换const
3.类型提升
4.算数类型转换或指针转换
5.类类型转换

void f();
void f(int);
void f(int,int);
void f(double,double);

//匹配到 f(double,double)
f(3.14);
//二义性,关于前一个参数f(int,int)更优,而后一个f(double,double)更优。
f(2,3.14);

void ff(int);
void ff(short);
void ff(float);

//匹配到ff(int),小整数型会直接提升到int
ff('a');
//二义性,字面值3.14的类型是double,存在多种可能的算数型转换
ff(3.14);

预处理器变量

预处理定义的5个用于程序调试很有用的名字。

__FILE__  文件名
__func__  存放当前函数的名字
__LINE__  存放当前行号
__TIME__  存放文件编译时间
__DATE__  存放文件编译日期

函数指针

函数指针指向的是函数,它的类型由返回类型和形参共同决定。

bool func(int,int);
// p指向一个函数,该函数参数是两个int型整数,返回值是bool
bool (*p)(int,int);

//把函数名当作值使用会自动转化为指针,以下两个赋值等价
p = func;
p = &func;

//可以直接用指向函数的指针调用该函数,以下3个调用也等价
bool b1 = func(0,0);
bool b2 = p(0,0);
bool b3 = (*p)(0,0);
// f的形参为1int型整数,返回值是一个指针,指向一个int*(int*,int)函数
int (*f(int))(int*,int);
// 等价写法
auto f(int) -> int*(int*,int
目录
相关文章
|
19天前
|
SQL Oracle 关系型数据库
[Oracle]面试官:你举例几个内置函数,并且说说如何使用内置函数作正则匹配
本文介绍了多种SQL内置函数,包括单行函数、非空判断函数、日期函数和正则表达式相关函数。每种函数都有详细的参数说明和使用示例,帮助读者更好地理解和应用这些函数。文章强调了字符串操作、数值处理、日期计算和正则表达式的使用方法,并提供了丰富的示例代码。作者建议读者通过自测来巩固学习成果。
15 1
[Oracle]面试官:你举例几个内置函数,并且说说如何使用内置函数作正则匹配
|
1月前
|
程序员 C++ 容器
在 C++中,realloc 函数返回 NULL 时,需要手动释放原来的内存吗?
在 C++ 中,当 realloc 函数返回 NULL 时,表示内存重新分配失败,但原内存块仍然有效,因此需要手动释放原来的内存,以避免内存泄漏。
|
1月前
|
存储 前端开发 C++
C++ 多线程之带返回值的线程处理函数
这篇文章介绍了在C++中使用`async`函数、`packaged_task`和`promise`三种方法来创建带返回值的线程处理函数。
47 6
|
1月前
|
C++
C++ 多线程之线程管理函数
这篇文章介绍了C++中多线程编程的几个关键函数,包括获取线程ID的`get_id()`,延时函数`sleep_for()`,线程让步函数`yield()`,以及阻塞线程直到指定时间的`sleep_until()`。
25 0
C++ 多线程之线程管理函数
|
1月前
|
编译器 C语言 C++
C++入门3——类与对象2-2(类的6个默认成员函数)
C++入门3——类与对象2-2(类的6个默认成员函数)
24 3
|
1月前
|
编译器 C语言 C++
详解C/C++动态内存函数(malloc、free、calloc、realloc)
详解C/C++动态内存函数(malloc、free、calloc、realloc)
177 1
|
1月前
|
存储 编译器 C++
C++入门3——类与对象2-1(类的6个默认成员函数)
C++入门3——类与对象2-1(类的6个默认成员函数)
33 1
|
1月前
|
编译器 C语言 C++
C++入门6——模板(泛型编程、函数模板、类模板)
C++入门6——模板(泛型编程、函数模板、类模板)
42 0
C++入门6——模板(泛型编程、函数模板、类模板)
|
3月前
|
存储 Java
【IO面试题 四】、介绍一下Java的序列化与反序列化
Java的序列化与反序列化允许对象通过实现Serializable接口转换成字节序列并存储或传输,之后可以通过ObjectInputStream和ObjectOutputStream的方法将这些字节序列恢复成对象。
|
13天前
|
存储 算法 Java
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
本文详解自旋锁的概念、优缺点、使用场景及Java实现。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?