目录
1. 命名空间 ::
2. using 声明
3. 结构体加强
(1)不需要加struct就可以定义变量
(2)结构体内可以写函数
4. 不能进行隐式转换,必须是显式转换
5. 三目运算符
6. C/C++中的const
7. 引用(重难点)
(1)引用可以作为一个已定义变量的别名
(2)当定义函数时,按引用传递
(3)建立数组引用
(4)引用的本质
(5)指针引用
(6)常量引用
(7)引用的使用
① 引用作为函数的参数
② 引用作为函数的返回值
8. 内联函数
9. 函数的默认参数
10. 函数的占位参数
11. 函数传参的三种方式
12. 创建一个学生类
1. 命名空间 ::
namespace A{ //A 是空间的名字
int a;
void func()
{}
}
(1)命名空间只能写在全局;
(2)可以嵌套;
namespace Aspace {
int a = 1;
namespace B {
int b;
}
}
(3)命名空间是开放的,可以随时加入新成员;
(4)命名空间可以取别名;
namespace newSpace = oldSpace; newSpace:新名字 oldSpace:旧名字
(5)分文件编写代码时,如果.h中有两个命名空间,但是里边的成员函数或变量重名时,在.cpp中实现函数时需要加上命名空间。eg:
test.h:
#pragma once #includeusing namespace std; namespace Space1 { void func(); } namespace Space2 { void func(); }
test.c:
#include "test.h"
void Space1 :: func() //需要在函数名之前加上命名空间的名字
{
cout << "func" << endl;
}
(6)作用域运算符 ::
eg:
#includeusing namespace std; //标准命名空间 namespace Aspace { int aa = 1; void func() { } namespace B { int b = 3; } } namespace Cspace { int c = 2 ; } int aa = 100; int main() { int aa = 10; cout << "aa =" << aa << endl; //就近原则,打印局部变量aa的值 cout << "::aa =" << ::aa << endl; //如果::前边没有东西,则表示取全局的作用域,打印全局变量的aa cout << "Cspace::c =" << Cspace::c << endl; //::前边加上命名空间的名字则打印命名空间中对应成员的值 cout << "Aspace::B::b =" << Aspace::B::b << endl; system("pause"); return EXIT_SUCCESS; }
输出为:
aa =10 ::aa =100 Cspace::c =2 Aspace::B::b =3
2. using 声明
#define _CRT_SECURE_NO_WARNINGS
#include
using namespace std;
namespace A {
int a = 1;
int b = 2;
int c = 3;
}
void test01()
{
//using声明是让命名空间中某个标识符可以直接使用
using A::a;
cout << a << endl;
int a = 50; //错误,因为using声明了某个变量,在该作用域内不能定义同名的变量
}
void test02()
{
//using 编译指令,让某个命名空间中的标识符都可以直接使用
using namespace A;
cout << a << endl;
int a = 10; //这里没错,因为这里类似于命名空间中的a为全局变量,而这个a是局部变量
}
3. 结构体加强
(1)不需要加struct就可以定义变量
struct Maker
{
char name[64];
int age;
};
void test()
{
Maker a;
}
(2)结构体内可以写函数
struct Maker2
{
int a;
void func()
{
cout << "func" << endl;
}
};
void test()
{
Maker2 a2;
a2.func();
}
4. 不能进行隐式转换,必须是显式转换
void test()
{
char* p = (char*)malloc(64);
}
5. 三目运算符
(1)不需要加struct就可以定义变量
struct Maker
{
char name[64];
int age;
};
void test()
{
Maker a;
}
(2)结构体内可以写函数
struct Maker2
{
int a;
void func()
{
cout << "func" << endl;
}
};
void test()
{
Maker2 a2;
a2.func();
}
4. 不能进行隐式转换,必须是显式转换
void test()
{
char* p = (char*)malloc(64);
}
5. 三目运算符
struct Maker2
{
int a;
void func()
{
cout << "func" << endl;
}
};
void test()
{
Maker2 a2;
a2.func();
}
4. 不能进行隐式转换,必须是显式转换
void test()
{
char* p = (char*)malloc(64);
}
5. 三目运算符
(1)C语言中,三目运算符返回的是右值,不能被赋值;
void test()
{
int a = 10;
int b = 20;
printf("%d",a > b ? a : b);
//(a > b ? a : b) = 100; //err
}
(2)C++中,三目运算符返回的是左值,是空间,可以被赋值;
void test()
{
int a = 10;
int b = 20;
(a > b ? a : b) = 100;
cout<<"a ="<
输出为:
a=10; b=100;
6. C/C++中的const
| C | C++ |
|---|---|
| const修饰的变量会被存储在只读数据段,只要有定义即分配内存空间 | 全局const当声明extern或者对变量取地址时,编译器才会分配存储地址,变量存储在只读数据段 |
| 局部const存储在堆栈区,不能直接改变变量的值,可以通过指针间接修改const的值 | 只有在分配了内存后,才能通过指针间接修改const变量的值。 ① 对于const int a = 10这种,编译器会进行优化,将a替换为10,类似于#define; ② 如果用一个变量初始化const,比如const int a = b,那么也会给a分配内存; ③ 对于类对象,也会分配内存,如下代码所示。 |
| 默认为外部连接,当两个c文件中都有同样的const变量时,编译器会报重定义错误 | 默认为内部连接,不会报重定义错误。如果想让C++中的const有外部链接,必须显式声明为:extern const int a = 10; |
const Person person; //未初始化age //person.age = 50; //不可修改 Person* pPerson = (Person*)&person; //指针间接修改 pPerson->age = 100; cout << "pPerson->age:" << pPerson->age << endl;
输出为:
pPerson->age:100
7. 引用(重难点)
(1)引用可以作为一个已定义变量的别名
void test02()
{
int a = 10;
int& b = a; //给a的空间取别名叫b
b = 100;
cout << a << endl;
}
void test02()
{
int a = 10;
int& b = a; //给a的空间取别名叫b
b = 100;
cout << a << endl;
}
输出为:100
而指针的写法是:
void test02()
{
int a = 10;
int* b = &a;
*b = 100;
}
(2)当定义函数时,按引用传递
void func(int &b)
{
b = 100;
}
void test()
{
int a = 10;
func(a);
cout << "a = " << a << endl;
}
输出为:a = 100
而C指针的写法是:
void func(int *b)
{
*b = 100;
}
void test()
{
int a = 10;
func(&a);
cout << "a = " << a << endl;
}
引用的注意:
- ① & 在此不是求地址运算,而是起标识作用;
- ② 引用创建时必须初始化;
- ③ 引用一旦初始化后不能改变它的指向
- ④ 必须引用一块合法的内存空间
(3)建立数组引用
int main()
{
int arr[] = { 1,2,3 };
//第一种方法
typedef int(Arr)[3]; //定义数组类型
Arr &arref = arr; //建立引用
//第二种方法,直接定义引用
int(&arref2)[3] = arr;
for (int i = 0; i < 3; i++)
{
cout << arref[i] << endl;
}
}
(4)引用的本质
C++编译器在编译过程中使用常指针作为引用的内部实现,因此引用所占用的空间大小与指针相同。
int main()
{
int a = 10;
int& aRef = a; //自动转换为int* const aRef = &a;这也能说明引用为什么必须初始化
aRef = 20; //内部发现aRef是引用,自动帮我们转换为: *aRef = 20;
}
如下图所示:
(5)指针引用
在C语言中,如果想改变一个指针的指向,而不是它所指向的内容,则会使用二级指针,如下:
void func(char** tmp)
{
char* p = (char*)malloc(64);
memset(p, 0, 64);
strcpy(p, "hello");
*tmp = p;
}
void test()
{
char* mp = NULL;
func(&mp);
cout << mp << endl;
}
改成引用的话:
void func(char* &tmp)
{
char* p = (char*)malloc(64);
memset(p, 0, 64);
strcpy(p, "hello");
tmp = p;
}
void test()
{
char* mp = NULL;
func(mp);
cout << mp << endl;
}
(6)常量引用
定义格式:
const int& ref = val;
int main()
{
//普通引用
int a = 10;
int& tmp = a;
tmp = 20;
//int &ref = 10; err,不能给字面量取别名
const int& tmp1 = 10; //可以给const修饰的引用赋予字面量
//编译器会把上边的代码变为:int x=10; const int &tmp1=x;
//tmp2 = 20; err
}
(7)引用的使用
① 引用作为函数的参数
void func(int& a, int& b)
{
int sum = a + b;
cout << "sum = " << sum << endl;
}
void test()
{
int a = 10;
int b = 20;
func(a, b);
}
② 引用作为函数的返回值
void func(int& a, int& b)
{
int sum = a + b;
cout << "sum = " << sum << endl;
}
void test()
{
int a = 10;
int b = 20;
func(a, b);
}
② 引用作为函数的返回值
如果从函数中返回一个引用,必须像从函数中返回一个指针一样对待。当函数返回时,引用关联的内存一定要存在。
int& func()
{
int b = 10; //不能返回局部变量的引用
int& p = b;
return p;
}
int& func2()
{
static int b = 10;
return b;
}
void test()
{
cout << "func=" << func() << endl;
func() = 100; //如果要函数当左值,那么该函数必须返回引用
cout << "func2()=" << func2() << endl;
}
8. 内联函数
内联函数为了继承宏函数的效率,没有函数调用时的开销,又可以像普通函数那样,可以进行参数、返回值类型的安全检查,又可以作为成员函数。
内联函数也占用空间,但是相对于普通函数,只是省去了函数调用时的压栈、跳转、返回的开销,可以理解为内联函数是“以空间换时间”。
在普通函数前加上 inline 关键字使之成为内联函数。但是必须注意,函数体和声明结合在一起,否则编译器将它作为普通函数来对待。
inline void func(int a); //该写法没有任何效果
类内部的内联函数:
类内部定义内联函数时并不必须要加 inline,任何在类内部定义的函数自动成为内联函数。
c++内联编译会有一些限制:
- 不能存在任何形式的循环语句;
- 不能存在过多的条件判断语句;
- 函数体不能过于庞大;
- 不能对函数进行取址操作;
9. 函数的默认参数
int func(int a, int b = 0) //b=0即为b的默认值
{
return a + b;
}
注意:
- 函数的默认参数从左向右,如果一个参数设置了默认参数,那么这个参数之后的参数都必须设置默认参数。
- 函数声明和函数定义不能同时设置默认参数。
10. 函数的占位参数
void func(int a, int b, int)
{
cout << "a+b = " << a + b << endl;
}
void func2(int a, int b, int=20)
{
cout << "a+b = " << a + b << endl;
}
int main()
{
func(10,20); //err,占位参数也是参数,必须传参数
func(10,20,30); //ok
func2(10,20); //ok
func2(10,20,30); //ok
return EXIT_SUCCESS;
}
后边讲的操作符重载的后置++要用到这个。
11. 函数传参的三种方式
值传递、指针传递、引用传递
//值传递
void swap(int a, int b)
{
int tmp = a;
a = b;
b = tmp;
}
//指针传递
void swap2(int *a, int *b)
{
int tmp = *a;
*a = *b;
*b = tmp;
}
//引用传递
void swap3(int &a, int &b)
{
int tmp = a;
a = b;
b = tmp;
}
void myprint(int& a, int& b)
{
cout << "a=" << a << "b=" << b << endl;
}
int main()
{
int a = 10;
int b = 20;
swap(a,b);
myprint(a, b);
swap2(&a,&b);
myprint(a, b);
swap3(a,b);
myprint(a,b);
}
上述三种交换结果,只有第一种值传递无法交换a,b的值。



