C++学习笔记02-结构基础(问题-解答自查版)

前言

以下问题以Q&A形式记录,基本上都是笔者在初学一轮后,掌握不牢或者频繁忘记的点

Q&A的形式有助于学习过程中时刻关注自己的输入与输出关系,也适合做查漏补缺和复盘。

本文对读者可以用作自查,答案在后面,需要时自行对照。

--

问题集

## 2022年6月9日 -《C++ Primer plus》第5~8章

Q1:下面语句的执行结果?(注意:逗号的优先级)

        int cats = 17, 240;

        int cats = (17, 240);

Q2:以下两个C++函数的定义?哪个正确?

        void sum_arr(int iarray[], int n){ }

        void sum_arr(int[] iarray, int n){ }

Q3:手写迭代器,代码中 const int *i 是什么含义?

void print_arr(const int * begin, const int * end){
   for (const int *i = begin; i != end; i++) 
        cout << *i << " ";
}

int main(){
    int arr[arrSize]= {1,2,3,4,5,6,7};
    print_arr(arr, arr + arrSize);   //优点:从 地址begin~地址end 的遍历
}

Q4:C++中,这样能修改const变量吗?

        const float gmoon =1.63;

        float *pm = &g_moon;

Q5:如何定义一个第一个参数接受二维数组的函数体?:int sum(  ,int size)

Q6:函数探幽——引用的本质?可以有空引用吗?

Q7:如何理解引用将两个变量 wallet1和wallet2 产生交换?

Q8: double refcube (const double &ra ); 入参 声明成这样有什么作用?

Q9:已知 double refcube (const double &ra ); 函数声明

        double z = refcube (x + 3.0); 这个调用正确吗?

         (注意本eg中:x是一个引用型double变量)

Q10:C++中,比较严谨的左值定义?

        另外地,有没有简单粗暴的理解方法?

Q11:已知 double refcube (double &ra ); 函数声明。

        什么时候编译器会让ra默认创建临时变量?(了解即可)

Q12:右值引用如何声明?一种特殊语法,使用在什么地方?

Q13:函数返回结构体引用变量的目的是什么?

Q14:将类对象传递给函数时,C++通常的做法是使用()

Q15:这个函数重载的方式正确吗?

 Q16:这个函数重载的是否正确?

        int func(int a);

        int func(const int a);

Q17:模版函数的两种写法?

Q18:显式模板化是什么?其函数的声明?

Q19:重载匹配的规则?

Q20:cout << lesser<> (m, n) << endl ;  这个语法是什么意思?

Q21:函数模板中遇到未知变量类型,该使用何种关键字进行?

ps:这个情境最主要是因为模版无法预知入参运算的结果,比如 int+float 和 int+long 就很不同

参考解答

Q1:下面语句的执行结果?

        int cats = 17, 240;

        int cats = (17, 240);

A1:

 Q2:以下两个C++函数的定义?哪个正确?

        void sum_arr(int iarray[], int n){ }

        void sum_arr(int[] iarray, int n){ }

函数的入参为数组的时候,入参应被视为数组本身,还是数组首地址?

A2:void sum_arr(int iarray[], int n){ }正确;

根据C++规则,入参为数组,入参 int iarray[] = 数组名 = 函数指针 = 其第一个元素的地址

也就是说:函数传递的实则为地址

这里补充了一个实验:

void sum_arr(int iarray[], int n){

    cout << 1;

}

void sum_arr(int * iarray, int n){

    cout << 2;

}

在这段代码中,函数 sum_arr 并不视为两种重载,而是视为重复定义,也就是其本质一样

void sum_arr(int iarray[ ], int n) 实际在编译时被转换成了 → void sum_arr(int * iarray, int n)

注意:在C++中,当且仅当用于函数头或函数原型中,int *arr 和 int arr []的含义才是相同的。它们都意味着 arr 是一个 int 指针。

  

 Q3:手写迭代器,代码中 const int *i 是什么含义?

void print_arr(const int * begin, const int * end){

   for (const int *i = begin; i != end; i++) 

        cout << *i << " ";

}


int main(){

    int arr[arrSize]= {1,2,3,4,5,6,7};

    print_arr(arr, arr + arrSize);   //优点:从 地址begin~地址end 的遍历

}

A3:const int *i 表示一个 指向 const int 的指针,意味着这个指针的位置不会发生改变。

Q4:这样能修改const变量吗?

        const float gmoon =1.63;

        float *pm = &g_moon;

A4:不可以,语法上直接报错,其正确格式:

        const float gmoon = 1.63;

        const float *pm = &g_moon;

C++禁止将 const 的地址赋给非 const 指针。// error: invalid conversion from 'const char*' to 'char*' [-fpermissive]

如果读者非要这样做,可以使用强制类型转换来突破这种限制,详情请参阅第15章中对运算符const_cast 的讨论,这个东西专门用来突破const界限。

Q5:如何定义一个第一个参数接受二维数组的函数体?:int sum(  ,int size)

A5:如下

ar2是指针而不是数组。还需注意的是,指针类型指出,它指向由 4 个int组成的数组

因此,指针类型指定了列数,这就是没有将列数作为独立的函数参数进行传递的原因。

Q6:函数探幽——引用的本质?可以有空引用吗?

A6:给变量取别名;

引用变量的主要用途是用作函数的形参,引用变量用作参数,函数将使用原始数据,而不是其副本

引用要求初始化的时候就产生“绑定”,不能跳过初始化。这个特性比较类似const指针

Q7:如何理解引用将两个变量 wallet1和wallet2 产生交换?

A7:在swapr()中,变量a和b是 wallet1 和 wallet2 的别名,所以交换a和b的值相当于交换 wallet1 和 wallet2 的值;

注意:引用是别名,而不是地址只是提供了一种方式来访问和操作它所绑定的对象。

这里有个习作,看看能不能看懂:

    int man = 233;        // 定义man

    int & robot = man;    // 定义引用变量 robot,绑定man,以后robot就是man的别名了

   

    vplus(robot);         // 给robot表示的变量输入vplus函数

    cout << man;         

}



void vplus (int & value){    // vplus:给入参表示的变量++; 即:给value表示的robot表示的man变量++

    value ++;                // 实际上,robot,man和vplus运行中的value指向了同一个值

}

Q8: double refcube (const double &ra ); 参数 声明成这样有什么作用?

A8:声明引用变量 &ra 是不可变的引用。引用型变量如果在函数体内部变来变去,外面的值也就发生变化了。

这个功能对于 ra 是一个double而言,实际上和值传递没有区别。

这个功能最有用的地方是用来引用struct或者class,如下:

之后在其中不用指针操作,而是可以直接在函数体内写 ft.name = "Joe"

Q9:接上面,已知 double refcube (const double &ra ); 声明

        double z = refcube (x + 3.0); 这个调用正确吗? (本eg:x是一个非const 的 double 引用变量)

A9:不正确,因为x+3不是一个变量。

        这里涉及了一个不容易被注意的规则:如果实参(double)与引用参数(const double &)不匹配,C++将生成临时变量。(具体的规则可以看Q11)

Q10:C++中,比较严谨的左值定义?

A10:定义比较简单,主要基于是否可被赋值,int a,以及 const int a; 都可以被视作左值

        较为粗暴的理解:

        C++中所有值必然属于左值或者右值
        在C++11中可以取地址的、有名字的就是左值
        反之,不能取地址的、没有名字的就是右值

Q11:已知 double refcube (double &ra ); 声明

        什么时候会让ra默认创建临时变量?(编译器差异,了解即可)

A11:目前,这种语法如果使用右值,已经不再是告警,而是直接报错:包括下面 c++ prime plus 书中的案例

旧版本两种情况:

        1)实参的类型正确,但不是左值;

        2)实参的类型不正确,但可以转换为正确的类型。

        总而言之,就是需要临时整一下,不能直接提供。

Q12:右值引用如何声明?一种特殊语法,使用在什么地方?

A12:用&&声明,

    int && ref = 7;

    cout << ref << endl;

允许将资源(如内存、文件句柄等)从临时对象转移到新对象,实现移动语义

Q13:函数返回结构体引用变量的目的是什么?

A13:为了效率,少一次拷贝。

Q14:将类对象传递给函数时,C++通常的做法是使用()

A14:引用

Q15:这个函数重载的方式正确吗?

A15:不正确。

Q16:这个函数重载的是否正确?

        int func(int a);

        int func(const int a);

A16:不正确,const 不会被认作区分。

Q17:模版函数的两种写法?

A17:

template <typename T>;

或者 template <class T>;  // 后者C++98老式风格

void Swap(T &a,T &b) ;

Q18:显式模板化是什么?其函数的声明?

A18:

Q19:重载匹配的规则?

A19:哪个最接近匹配哪个。默认优先级:正常函数 > 模版函数

Q20:cout << lesser<> (m, n) << endl ;  这个语法是什么意思?

A20:主要是对于有函数模板和正常函数并存的情况,手动选择函数模板。

Q21:函数模板中遇到未知变量类型,该使用何种关键字进行?

ps:这个情境最主要是因为模版无法预知入参运算的结果,比如 int+float 和 int+long 就很不同

A21:通过关键字 decltype(x) y ,make y's type same as x;这个语法有点 auto y as x 的意思;

decltype 的内在本质是一个查表逻辑

Q22:函数模板中遇到未知返回值类型,该使用何种关键字进行?

ps:比起上一个问题,这个的难度在于考虑 x和y 甚至没有声明,编译器一无所知

后置返回类型 的内在本质是让 x和y 两个入参具备了作用域前提

A22:auto func()  -> TYPE,

// 这里的 TYPE 可以是传统类型,也可以是 decltype(入参)

经测验,这个代码可以运行正常(没有用decltype):

template <typename T1, typename T2>

auto add(T1 a, T2 b){     //   auto add(T1 a, T2 b)  -> decltype(a+b)  is also correct

    return a+b;

}

int main(){

    int a = add(5,6);

    double b = add(5, 6.2);

    cout << a << endl;

    cout << b << endl;

}

  • 16
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值