C++基础入门(02)_引用

C++基础入门(02)_引用

Wed Aug 21 2024
BigWind
12 minutes
1831 words

01.引用的使用场景(重点)#

1.引用作为函数参数

PLAINTEXT
1
2
3
4
5
6
7
8
9
10
11
12
13
//1.引用作为函数参数
void func(int &a, int &b)
{
    int sum = a + b;
    cout << "sum=" << sum << endl;
}

void test01()
{
    int a = 10;
    int b = 20;
    func(a, b);
}

2.引用作为函数的返回值

PLAINTEXT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//2.引用作为函数的返回值
int& func2()
{
    int b = 10;//注意1:不要返回局部变量的引用
    int &p = b;
    return p;
}
int &func3()
{
    static int b = 10;
    return b;
}
void test02()
{
    int &q = func2();
    q = 100;
    cout << q << endl;

    func2() = 200;
    cout << q << endl;
////---------上面的代码是错误,只是编译器没有检测出来
    cout << "func2="<<func2() << endl;

    func3() = 100;//注意2:如果要函数当左值,那么该函数必须返回引用
    cout << "func3()=" << func3() << endl;
}

02.常量引用(了解)#

PLAINTEXT
1
2
3
int &ref=10;//err
const int &ref2=10;//ok
原理是:int tmp=10;const int &ref=tmp;

03.内联函数(了解)#

1.宏函数的缺陷

PLAINTEXT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#define ADD(x,y) x+y
//在普通函数前面加上inline是向编译器申请成为内联函数
//注意:加inline可能成为内联函数,可能不成为内联函数
inline int Add(int x, int y)
{
    return x + y;
}

void test()
{
    //10+20*2
    int ref = ADD(10, 20) * 2;
    cout << "ref=" << ref << endl;

    int ref2 = Add(10, 20) * 2;
    cout << "ref2=" << ref2 << endl;
}

#define COMAPD(x,y) ((x)<(y)?(x):(y))
inline int func(int x, int y)
{
    return x < y ? x : y;
}
void test02()
{
    int a = 1;
    int b = 3;
    //                        ((++a)<(b)?(++a):(b))      
    //cout << "COMAPD(x,y)=" << COMAPD(++a, b) << endl;//3
    cout << "func=" << func(++a, b) << endl;//2
}

2.什么情况不会成为内联函数

​ 1.存在过多的条件判断语句

​ 2.函数体过大

​ 3.对函数进行取址操作

​ 4.存在任何形式的循环语句

3.内联函数的好处

​ 1.有宏函数的效率,没有宏函数的缺点

​ 2.类的成员函数默认加上inline

4.在普通函数前面加上inline是申请成为内联函数

04.函数的默认参数(重点)#

1.函数的默认参数就是给函数的形参赋值

PLAINTEXT
1
2
3
4
5
6
7
8
9
10
11
12
int myFunc(int a, int b = 0)//int b=0;这就是函数的默认参数,不一定是0
{
    return a + b;
}
void test01()
{
    //函数的默认参数的作用
    //当函数内常要用到形参的某个值,但偶尔要使用其他值
    //增加函数的灵活性
    cout << myFunc(10, 20) << endl;
    cout << myFunc(10)<< endl;
}

2.函数的默认参数的注意事项

PLAINTEXT
1
2
3
4
5
6
7
8
9
10
11
//注意1:函数的默认参数后面的参数必须都是默认参数
int myFunc2(int a, int b = 0, int c=2,int d=3)
{
    return a + b + c + d;
}
//注意2:函数的声明和实现不能同时有函数的默认参数
void myFunc3(int a, int b);
void myFunc3(int a, int b = 0)
{

}

05.函数的占位参数(了解)#

PLAINTEXT
1
2
3
4
5
6
7
8
9
10
//函数的占位参数,占位参数在后面运算符重载时区分前加加或后加加
void func(int a,int=10)//占位参数也有默认值
{

}

void test02()
{
    func(10);
}

函数的默认参数和占位参数的混搭

PLAINTEXT
1
2
3
4
5
6
7
8
9
10
11
//占位参数和默认参数混搭
void func2(int=10, int a=20)
{

}
void test03()
{
    func2();
    func2(10);
    func2(10,30);
}

06.函数重载(重点)#

1.函数重载是:允许函数名相同,这种现象叫函数重载

2.函数重载的作用:是为了方便使用函数名

3.函数重载的条件:同一个作用域,参数的个数不同,参数的顺序不同,参数的类型不同

PLAINTEXT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//参数的个数不同
void func()
{
    cout << "func()" << endl;
}

void func(int a)
{
    cout << "func(int a)" << endl;
}

//参数的类型不同
void func(char c)
{
    cout << "func(char c)" << endl;
}
//参数的顺序不同
void func(int a, double b)
{
    cout << "func(int a, double b)" << endl;
}
void func(double b, int a)
{
    cout << "func(double b, int a)" << endl;
}

4.调用重载函数的注意:

严格的类型匹配,如果类型不匹配,那么尝试转换,转换成功就掉用,失败就报错

PLAINTEXT
1
2
3
4
5
6
7
8
9
10
11
12
void test01()
{
    int a = 10;
    double b = 3.14;

    func();
    //func(b);// err double转换不了成为int或char
    func(a, b);
    func(b, a);
    char c = 'c';
    func(c);//char转换int成功,调用int参数的函数
}

5.函数重载和函数的默认参数一起使用,需要注意二义性问题

PLAINTEXT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//函数重载和函的默认参数一起使用
void myfunc(int a, int b = 0)
{
    cout << "myfunc(int a, int b = 0)" << endl;
}

void myfunc(int a)
{
    cout << "myfunc(int a)" << endl;
}

void test02()
{
    //myfunc(10); err,二义性问题,不知道调用哪个函数
}

6.函数的返回值不作为函数重载的条件

编译器是通过你调用函数时,传入的参数来判断调用重载的哪个函数,我们调研函数时不需要写返回值,所以返回值不能成为函数重载的条件

07.函数重载的原理(重点)#

1.函数重载的原理是在汇编时,给各个函数取别名,C语言不能重载的原因是没有取别名

2.生成汇编文件:gcc -S test.c -o test.s g++ -S test.cpp -o test2.s

3.查看内容:type 文件名

08.C++调用C语言的函数(重点)#

1.C++的函数在汇编时,会给函数取别名,C语言的不会,这时,如果C++来调用C语言的函数,C++会去找取了别名的函数,但是C语言没有取别名,这时会出错

PLAINTEXT
1
2
3
4
5
6
7
8
9
10
11
12
13
test.h文件中

//这是告诉C++编译器,找下面的函数,要以C语言的方式去寻找
#ifdef __cplusplus
extern "C"
{
#endif
    void func();//C语言的函数声明


#ifdef __cplusplus
}
#endif

09.类和对象的概念(重点)#

1.类是自定义数据类型,是C语言的结构体进化而成的

2.对象是类实例化出的,用数据类型定义一个变量

PLAINTEXT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Maker//这个是类
{
public:
    int a;//成员属性(成员变量)
    void func()//成员方法(成员函数)
    {
        cout << "func" << endl;
    }
};

int main()
{
    Maker m;//m就是对象

    system("pause");
    return EXIT_SUCCESS;
}

10.类的封装(重点)#

1.封装是把属性(变量)和方法(函数)封装到类内,然后给这些数据赋予权限

2.为什么要有封装

​ 1.防止乱调用函数和变量,出现错误

​ 2.维护代码更方便

3.权限

PLAINTEXT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
//封装:1,把属性和方法放到类中,2.给这些数据赋予权限
class Maker
{
public://公有权限
    void set(string Name,int Id)
    {
        id = Id;
        name = Name;
    }
    void printMaker()
    {
        cout << "id=" << id << " name=" << name << endl;
    }
private://私有
    int id;
    string name;

protected://保护
    int a;
};
//继承
class Son :public Maker
{
    void func()
    {
        a = 20;//子类的类内可以方法父类的保护权限的成员

    }
};
//类外不能访问私有权限的成员
//类外可以访问公有权限的成员
//类外不能访问保护权限的成员
//子类的类内可以方法父类的保护权限的成员
//类内是没有权限之分

void test()
{
    Maker m;
    m.set("小花",1);
    m.printMaker();


}

4.尽量把属性设置为私有权限

1.可以控制属性的读写权限

2.可赋予客户端访问数据的一致性

3.可以保护属性的合法性

11.类和结构体的区别(了解)#

结构体的默认权限是公有的,类的默认权限是私有的