[c++语法学习]Day11:c++面向对象 1
6. auto关键字
auto 自动推导类型,当然了在变量类型很长的时候使用会很方便
// 1.auto 类型自动推导
int a = 1;
int b = a;
auto c = a;
auto d = 1 + 1.1;
// 打印变量类型 typeid
cout << typeid(c).name() << endl;
cout << typeid(d).name() << endl;
// 2.指定类型
int x = 10;
auto& y = x; // 指定为引用
auto* z = x; // 指定为指针
auto不能做返回值和函数的参数 (c++ 11)最新版本的不一定
7. 基于范围的 for 循环
// c 风格的循环,(话说我之前居然没使用过这样的判断条件)
int arr[] = {1,2,3,4,5,6}
for(int i = 0;sizeof(arr)/sizeof(int);i++){arr[i] += 2;
}
// 1.适用于数组
// c++ 范围for 语法糖
// 自动迭代,自动判断结束
for(auto e : arr){cout << e << " ";
}
// 2.修改数据
for(auto& e : arr){cout << e << " ";
}
// 3.适用条件
// for 循环迭代的范围必须是确定的
void TestFor(int arr[]){for(auto& e : arr){cout << e << endl;}
}
8. 内联函数
1.宏定义(宏函数)
不需要加分号,宏本质就是替换,会在预处理阶段对代码进行替换,进行展开;宏定义注意加括号
优点:主要的目的是为了减少函数的创建,不需要建立栈帧,提高调用效率
缺点:复杂,容易出错,可读性差,不能调试
// 这里为什么x,y也要加括号,是因为这里x,y有可能是表达式
#define ADD(x,y) (((x)+(y))*10)
2.内联函数(inline)
适用于短小,频繁调用的函数。本质也是在源代码直接替换
如果函数过大,会导致代码臃肿,最终生成的可执行程序变大。
inline 对于编译器来说只是一个建议,最终是否能成为inline,由编译器自己决定
向类似的函数加了 inline 编译器也会被否决:
1.比较长的函数
2.递归函数
3.默认debug版本下inline不会生效,因为就没办法调试内联函数了
inline int Add(int x, int y) {return (x + y) * 10;
}
注意:内联函数声明和定义不要分离,直接在 Func.h 文件定义
// Func.h
#include<iostream>
using namespace std;inline void add1(int x, int y) {cout << x + y << endl;
}
9. 指针空值(nullptr)
c++ 中 nullptr 代表空指针,NULL 被宏定义为0
// c++ 中不要求一定要有变量来接受值
void f(int)
{cout << "f(int)" << endl;
}
void f(int*)
{cout << "f(int*)" << end;
}
f(0);
f(NULL); // 宏定义为 0
f(nullptr);
三、c++ 面向对象
1. struct
在c++中 结构体升级为类,struct 具有类的特性,可以存在成员变量和成员函数。当然struct仍然具有 c 的特性
struct 的默认访问权限为public ,而class 默认为private
struct 也可以使用 访问限定符
struct Stack
{// 成员函数void Init(int x = 4){}void Push() {}void Destory() {free(a);a = nullptr;top = capacity;}// 成员变量int* a;int top;int capacity;
};
2.class 类 (上)
1. 访问限定符
protected 和 private 类别差不多 在继承时有区别

class Stack
// 类域
{
public:// 成员函数void Init(int x = 4){}void Push() {}void Destory() {free(a);a = nullptr;top = capacity;}
private:// 成员变量int* a;int top;int capacity;
};
2. 成员函数的声明和定义分离
需注意:成员函数如果在类中定义,编译器可能会将其当成 内联函数 inline 处理。当然具体要看编译器。
class Stack
{
public:// 成员函数void Push();
private:// 成员变量int* a;int top;int capacity;
};
// 函数的定义
void Stack::Push() {cout << "push x" << endl;
}
3. 关于命名
class Date
{
public:void Init(int year) {_year = year;}
// 对于成员变量,为了区分可以在命名时添加一个 _
private:int _year; // 或者在后面加一个_int _month;int _day;
};
4. 封装
面向对象的三大特征:封装,继承,多态
5. 类的作用域
域:局部域 全局域 命名空间域 类域
局部域与全局域会影响变量的生命周期
- 类是对对象进行描述的,是一个模型一样的东西,限定了类有哪些成员,定义出一个类并没 有分配实际的内存空间来存储它;比如:入学时填写的学生信息表,表格就可以看成是一个 类,来描述具体学生信息。 类就像谜语一样,对谜底来进行描述,谜底就是谜语的一个实例。 谜语:“年纪不大,胡子一把,主人来了,就喊妈妈” 谜底:山羊
- 一个类可以实例化出多个对象,实例化出的对象 占用实际的物理空间,存储类成员变量
// 类的实例化
Stack st1;
// ❌错误
Stack::top = 1; // 声明不能存数据
6. 类对象模型
1. 类对象大小
在计算类的大小时,只需要计算成员变量的大小
对象中只存储了成员变量,没有存储成员函数
同一个类的对象他们使用同样的成员函数,重复开辟会浪费空间
因此,类只保存成员变量,成员函数存放在公共的代码段
2. 内存对齐
计算内存时要考虑内存对齐,每一个变量在内存中的偏移量只能是其自身的整数倍;很关键
因此,在声明变量时,char shot应放在一起
- CPU 并非以字节为单位读取内存,而是以“字”(word)为单位。在32位系统上,一个字是4字节;在64位系统上,通常是8字节。
- 如果数据在内存中是对齐的,CPU 可以在一个读写周期内完成访问。
- 如果数据是未对齐的(例如,一个4字节的
int
存储在地址0x3处),CPU 需要执行两次内存访问(一次读取地址0x0-0x3,一次读取地址0x4-0x7),然后拼接出正确的数据。这个过程非常缓慢。 - 注意:空类(没有成员变量的类)所占空间为 1 字节;
// 1.
class A1
{
public:void PrintA() {cout << _a << endl;}
private:int _a;short _b;char _ch2;char _ch1;long long _c;short _ch3;int _d;
};
// vs 默认为8字节是一个字
// 4 + 2 + 1 + 1 + 8 + 2 + 填充(2) + 4// 2. 空类 没有成员变量的类
// 需要一字节,为了占位,表示对象存在
// 不存储有效数据
class A2 {};
7. this 指针
1. this介绍
当成员函数要去访问自己类中的成员变量时,没有显式的传递参数和传递指针,那么成员变量是如何区分不同的对象的?
C++编译器给每个“非静态的成员函数“增加了一个隐藏 的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中所有“成员变量” 的操作,都是通过该指针去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成。
class A1
{
public:void PrintA() {cout << _a << endl;}void Print() {cout << this->_a << endl;}
// 编译器会处理为如下形式
// 注意 this 是被 const 修饰的,本身不可以修改,但是其指向的内容可以修改
/* void Print(A1* const this) {cout << this->_a << endl;}
*/
private:int _a;
};
2. this 指针存在哪里 (对象里面 栈 堆 静态区 常量区)
this指针本质就是一个形参,所以this指针就和普通函数一样存在函数调用的栈帧中