内联函数(inline)
内联函数其实是声明,只能放在头文件里,不能放在实现(定义)里。
类在头文件里声明函数时直接写上body,那么这个函数其实就是inline的。
如果要在类中指明一个函数时inline的,只需要在头文件中函数声明的下面直接写上其实现,如下:
引用
int a = 5;
int c = 6;
int &b = a;//将引用与变量关联起来
b = c;
cout << a << "\t" << b << endl;
输出的日志如下:
6 6
所以这也验证了引用一旦被关联就将一直效忠于它。
不可用直接引用常量(字面量)
double& d = 12.3;//错误
d=111;//违背了常量的基本概念
const double& d = 12.3;//正确
原理:因为引用是别名,所以当引用就赋值为常量以后,那就意味着引用不能被重新赋值,这就违背了引用的定义。所以引用不允许在初始化时赋值常量。如果非要在初始化时赋值常量可以在引用前添加const关键字,表示这是一个不可变引用。
注意:当我们对引用进行重新赋值时,也会改变初始化变量的值。
引用参数
void swap1(int, int);//普通
void swap2(int *, int *);//指针
void swap3(int &, int &);//引用
int main() {
int a = 10, b = 5;
cout << "a和b的内存地址:" << &a << "\t" << &b << endl;
cout << "\n"<<endl;
swap1(a, b);
cout << "执行swap1后的a b的值:" << a << "\t" << b << endl;
cout << "\n"<<endl;
swap2(&a, &b);
cout << "执行swap2后的a b的值:" << a << "\t" << b << endl;
cout << "\n"<<endl;
swap3(a, b);
cout << "执行swap3后的a b的值:" << a << "\t" << b << endl;
return 0;
}
//复制拷贝变量值 不会影响原来的值
void swap1(int num1, int num2) {
cout << "num1和num2的内存地址:" << &num1 << "\t" << &num2 << endl;
int temp;
temp = num1;
num1 = num2;
num2 = temp;
}
//复制拷贝变量地址,对地址内的值进行交换会改变原来的值
void swap2(int *p1, int *p2) {
cout << "p1和p2的内存地址:" << &p1 << "\t" << &p2 << endl;
cout << "p1和p2的值:" << p1 << "\t" << p2 << endl;
int temp;
temp = *p1;
*p1 = *p2;
*p2 = temp;
}
//复制拷贝变量本身,即内存地址也一致,其实是指针的高级实现
void swap3(int &ref1, int &ref2) {
cout << "ref1和ref2的内存地址:" << &ref1 << "\t" << &ref2 << endl;
cout << "ref1和ref2的值:" << ref1 << "\t" << ref2 << endl;
int temp;
temp = ref1;
ref1 = ref2;
ref2 = temp;
}
输出日志如下:
a和b的内存地址:0x61ff0c 0x61ff08
num1和num2的内存地址:0x61fef0 0x61fef4
执行swap1后的a b的值:10 5
p1和p2的内存地址:0x61fef0 0x61fef4
p1和p2的值:0x61ff0c 0x61ff08
执行swap2后的a b的值:5 10
ref1和ref2的内存地址:0x61ff0c 0x61ff08
ref1和ref2的值:5 10
执行swap3后的a b的值:10 5
换一种方式理解函数传参:
下面我说的其实针对任何编程语言都是适用的。如果你对内存结构有过了解的话就会知道,我们的函数其实运行在虚拟机栈中,每个函数其实就是一个栈桢,当我们调用函数的时候,栈桢会入栈,函数执行完出栈。在函数中定义的变量都是临时变量,生命周期就是函数的执行周期。了解这些之后,我们再来看方法调用传参就会有一种新的理解。首先我们在函数中定义的形参它也是属于临时变量,所以他在函数中定义的临时变量唯一的不同点事不需要我们手动去初始化,因为在函数调用的时候它已经被初始化过了,还有一点,那就是其实所有的函数调用都是变量传值函数调用。所以我们来看一下上面的三个例子:
1.普通变量函数调用:我们将变量的值拷贝一份,保存在栈桢中并赋值给了临时变量,所以当我们对临时变量进行任何的操作其实都不会影响外部变量的值。
2.指针变量函数调用:我将变量的内存地址拷贝一份,保存在栈中并赋值给了指针,所以当我们对指针所指向的内存空间进行操作时也就影响了所有指向同一内存空间的变量。
3.引用变量函数调用(传指针的语法糖):我们传引用的时候比较特殊,无论你传值还是传指针,函数都会生成一个临时变量,但传引用时,不会生成临时变量,你可以把引用当做语法糖,但传引用主要是它不生成临时变量,不进行返回值copy等,速度快。实际上,你也可以把引用看做是通过一个常量指针来实现的,它只能绑定到初始化它的对象上
参数默认值
函数模板
面向对象
C++对象创建
1.创建头文件
hero.h
#ifndef DEMO_HERO_H
#define DEMO_HERO_H
#include <string>
#include <iostream>
using namespace std;
class Hero {
private:
string name;
public:
Hero();
const string &getName() const;
void setName(const string &name);
void attack();
};
#endif //DEMO_HERO_H
2.创建实现文件
hero.cpp
#include "Hero.h"
Hero::Hero() {
}
void Hero::attack() {
cout << "ssss" << endl;
}
const string &Hero::getName() const {
return name;
}
void Hero::setName(const string &name) {
Hero::name = name;
}
3.对象创建和调用
main.cpp
#include "Hero.h"
int main() {
Hero hero;
hero.attack();
hero.setName("66666");
cout << "姓名是:" << hero.getName() << endl;
return 0;
}
构造函数
带参构造函数
创建对象的2中方式:
Student s1;//栈中分配内存 栈内存容量有限 一般不推荐使用
Student s2 = new Student(); //堆内存中分配内存 当对象不再使用时 要及时释放内存 delete s2
析构函数
this指针
const
const如果位于前面则对象是const,位于后面则指针是const。**
实例:
char *s中的s是指针,而指针是指向一块内存区域,它指向的内存区域的大小可以随时改变,而且当指针指向常量字符串时,它的内容是不可以被修改的,否则在运行时会报错。
char s[]中的s是数组首地址,而数组首地址对应着一块内存区域,其地址和容量在生命期里不会改变,只有数组的内容可以改变。
深入 char * ,char ** ,char a[ ] ,char *a[] 内核
注意:C语言中操作字符串是通过它在内存中的存储单元的首地址进行的,这是字符串的终极本质
int main() {
//指针数组 []的优先级高于* 所以 他是一个数组,然后数组中保存的类型是char *
char *array[] = {"aaa", "bbb", "ccc"};
cout << sizeof(array) << endl; // 12 因为array是数组 保存的是指针 所以长度为3*4=12;
char **ptr_array = array;
cout << ptr_array << "\t" << *ptr_array << endl;
int a = 1, b = 2, c = 3;
int *iarray[] = {&a, &b, &c};
int **ptr_iarray = iarray;
cout << ptr_iarray << "\t" << *ptr_iarray << "\t" << **(++ptr_iarray) << endl;
return 0;
}
log:
12
0x63fefc aaa
0x63fee8 0x63fef4 2