Table of Contents:

void的使用

如果函数没有返回值,那么应声明为void类型
在C语言中,凡不加返回值类型限定的函数,就会被编译器作为返回整型值处理。但是许多程序员却误以为其为void类型。例如:

add ( int a, int b )
{
  return a + b;
}
int main(int argc, char* argv[])
{
  printf ( "2 + 3 = %d", add ( 2, 3) );
}
//程序运行的结果为输出:2 + 3 = 5

这说明不加返回值说明的函数的确为int函数
林锐博士《高质量C/C++编程》中提到:“C++语言有很严格的类型安全检查,不允许上述情况(指函数不加类型声明)发生”。
如果函数没有返回值,一定要声明为void类型。这既是程序良好可读性的需要,也是编程规范性的要求。
另外,加上void类型声明后,也可以发挥代码的"自注释"作用。代码的“自注释”即代码能自己注释自己。
如果函数的参数可以是任意类型指针,那么应声明其参数为void *

C++输入输出(cin和cout)

cout 和 cin 都是 C++ 的内置对象,而不是关键字。cout 和 cin 就分别是 ostreamistream 类的对象,只不过它们是由标准库的开发者提前创建好的,可以直接拿来使用。这种在 C++ 中提前创建好的对象称为内置对象
推荐大家使用 cin、cout,它们比C语言中的 scanf、printf 更加灵活易用

C++ new和delete运算符简介

在C++中,建议使用 new 和 delete 来管理内存,它们可以使用C++的一些新特性,最明显的是可以自动调用构造函数和析构函数.
c11中增加了智能指针,可以用它来代替new和delete。
在栈上的对象创建的时候调用构造函数和出作用域的时候调析构函数。
原理:编译器通过对程序的语法结构、作用域规则以及生成的中间代码的分析,确定了每个对象的作用域范围和何时出作用域,从而在适当的位置自动生成析构函数的调用代码。

C++函数的默认参数

C++规定,默认参数只能放在形参列表的最后,而且一旦为某个形参指定了默认值,那么它后面的所有形参都必须有默认值。
在以后设计类时你将发现,通过使用默认参数,可以减少要定义的构造函数、方法以及方法重载的数量。

到底在声明中还是定义中指定默认参数?
放到头文件中就行
C++ 规定,在给定的作用域中只能指定一次默认参数
编译器使用的是当前作用域中的默认参数。站在编译器的角度看,它不管当前作用域中是函数声明还是函数定义,只要有默认参数就可以使用。
不过有一点需要注意,在给定的作用域中一个形参只能被赋予一次默认参数

C++函数重载详解

参数列表又叫参数签名,包括参数的类型、参数的个数和参数的顺序,只要有一个不同就叫做参数列表不同。
重载的结果是让一个函数名拥有了多种用途,使得命名更加方便,调用更加灵活
在使用重载函数时,同名函数的功能应当相同或相近,不要用同一函数名去实现完全不相干的功能,虽然程序也能运行,但可读性不好,使人觉得莫名其妙。

重载决议
C++代码在编译时会根据参数列表对函数进行重命名,例如void Swap(int a, int b)会被重命名为_Swap_int_int,void Swap(float x, float y)会被重命名为_Swap_float_float。当发生函数调用时,编译器会根据传入的实参去逐个匹配,以选择对应的函数,如果匹配失败,编译器就会报错,这叫做重载决议(Overload Resolution)
不同的编译器有不同的重命名方式,这里仅仅举例说明,实际情况可能并非如此。
从这个角度讲,函数重载仅仅是语法层面的本质上它们还是不同的函数,占用不同的内存,入口地址也不一样

C++函数重载过程中的二义性和类型转换

函数调用时编译器会根据传入的实参的个数、类型、顺序等信息去匹配要调用的函数,这在大部分情况下都能够精确匹配。
但当实参的类型和形参的类型不一致时情况就会变得稍微复杂,例如函数形参的类型是int,调用函数时却将short类型的数据交给了它,编译器就需要先将short类型转换为int类型才能匹配成功。 但是类型转换会为重载决议造成困惑,不知道该确定哪一个函数,于是会造成编译错误。

#include <iostream>
using namespace std;
//1号函数
void func(char ch){
    cout<<"#1"<<endl;
}
//3号函数
void func(long m){
    cout<<"#3"<<endl;
}
//4号函数
void func(double f){
    cout<<"#4"<<endl;
}
int main(){
    short s = 99;
    float f = 84.6;
 
    func('a');
    func(s);
    func(49);
    func(f);
    return 0;
}

这段代码在编译时发生了错误,大概的意思是:func(s)和func(49)这两个函数发生调用错误,它们可以匹配三个重载函数中的任何一个,编译器不知道如何抉择。

变量检测增强

在C语言中,重复定义多个同名的全局变量是合法的
在C++中,不允许定义多个同名的全局变量
C语言中多个同名的全局变量最终会被链接到全局数据区的同一个地址空间上

int g_var;
int g_var = 1;

C++直接拒绝这种二义性的做法。

C++中的布尔类型

C++在C语言的基本类型系统之上增加了bool
C++中的bool可取的值只有true和false
C++编译器会在赋值时将非0值转换为true,0值转换为false

三目运算符的增强

通常情况下,判断某个表达式是左值还是右值,最常用的有以下 2 种方法:
* 可位于赋值号(=)左侧的表达式就是左值;反之,只能位于赋值号右侧的表达式就是右值
* 有名称的、可以获取到存储地址的表达式即为左值;反之则是右值。

三目运算C语言返回变量的值,C++语言是返回变量本身
C语言中的三目运算符返回的是变量值,不能做为左值使用,C++可以做左值
三目运算符可能返回的值中如果有一个是常量值,则不能作为左值使用
左值 能被放在 = 做值 称为左值,当左值的条件, 这段内存空间可以被写

(a < b ? a : b ) = 30;// c++做的手脚 *((a < b ? &a : &b ))=30
(a < b ? 1 : b ) 有常量了就不能做左值了

struct类型的加强

C语言的struct定义了一组变量的集合,C编译器并不认为这是一种新的类型
C++中的struct是一个新类型的定义声明
在C中定义一个结构体类型要用typedef:

typedef struct Student
{
 int a;
}Stu;

于是在声明变量的时候就可:Stu stu1; 如果没有typedef就必须用struct Student stu1;来声明