创作过程中难免有不足,若您发现本文内容有误,恳请不吝赐教。
提示:以下是本篇文章正文内容,下面案例可供参考
一、内联函数
1.铺垫
#include<iostream>
//实现一个ADD的宏函数
//#define ADD(x, y) x+y //错解1
//#define ADD(x, y) (x+y) //错解2
#define ADD(x,y) ((x)+(y)) //正解
int main()
{
ADD(1, 2);
printf("%d\n", ADD(1, 2));
printf("%d\n", ADD(1, 2)*3); //错解1调用:1+2^3
int a = 1, b = 2;
ADD(a | b, a & b); // (a|b + a&b) //错解2调用:+运算符比|和&高
}
c语言的宏在写代码的时候容易出现错误,c++对c语言的宏进行优化处理。
2.概念
以
inline
修饰
的函数叫做内联函数,
编译时
C++
编译器会在
调用内联函数的地方展开
,没有函数调 用建立栈帧的开销,内联函数提升程序运行的效率。
#include<iostream>
int add(int x, int y)
{
return x + y;
}
int main()
{
int ret = add(1, 2);
printf("%d\n", ret);
return 0;
}
如果在上述函数前增加
inline
关键字将其改成内联函数,在编译期间编译器会用函数体替换函数的
调用。
查看方式:
1.
在
release
模式下,查看编译器生成的汇编代码中是否存在
call Add
2.
在
debug
模式下,需要对编译器进行设置,否则不会展开
(
因为
debug
模式下,编译器默认不
会对代码进行优化)
#include<iostream>
inline int add(int x, int y)
{
return x + y;
}
int main()
{
int ret = add(1, 2);
printf("%d\n", ret);
return 0;
}
3.特性
1. inline是一种以空间换时间的做法,如果编译器将函数当成内联函数处理,在编译阶段,会 用函数体替换函数调用,缺陷:可能会使目标文件变大,优势:少了调用开销,提高程序运行效率。
2. inline对于编译器而言只是一个建议,不同编译器关于inline实现机制可能不同,一般建 议:将函数规模较小(即函数不是很长,具体没有准确的说法,取决于编译器内部实现)、不是递归、且频繁调用的函数采用inline修饰,否则编译器会忽略inline特性。
3. inline不建议声明和定义分离,分离会导致链接错误。因为inline被展开,就没有函数地址了,链接就会找不到。
#include<iostream>
#include"Fun.h"
int main()
{
f(1);
return 0;
}
//Func.cpp
#include"Fun.h"
void f(int i)
{
cout << "fun(int i)" << i << endl;
}
//Func.h
#pragma once
#include<iostream>
using namespace std;
inline void f(int i);
运行报错:
#include<iostream>
#include"Fun.h"
int main()
{
//f(1);
fx();
return 0;
}
//Func.cpp
#include"Fun.h"
void f(int i)
{
cout << "fun(int i)" << i << endl;
}
void fx()
{
// 既有声明,也有定义,是直接展开
f(1);
}
//Func.h
#pragma once
#include<iostream>
using namespace std;
inline void f(int i);
void fx();
运行结果:
4.对比
1.宏的优缺点?
优点:
1.
增强代码的复用性。 2.提高性能。
缺点:
1.
不方便调试宏。(因为预编译阶段进行了替换)
2.导致代码可读性差,可维护性差,容易误用。
3.
没有类型安全的检查 。
C++
有哪些技术替代宏
?
1.
常量定义 换用
const enum 2. 短小函数定义 换用内联函数
二、auto关键字
1.【注意】
使用
auto
定义变量时必须对其进行初始化,在编译阶段编译器需要根据初始化表达式来推导
auto
的实际类型
。因此
auto
并非是一种
“
类型
”
的声明,而是一个类型声明时的
“
占位符
”
,编译器在编
译期会将
auto
替换为变量实际的类型
2.
用auto声明指针类型时,用auto和auto*没有任何区别,但用auto声明引用类型时则必须加&
#include<iostream>
#include<vector>
using namespace std;
int main()
{
int a = 0;
auto b = a;
auto c = &a;
auto& d = a;
std::vector<std::string> v;
//std::vector<std::string>::iterator it = v.begin();
auto it = v.begin();
cout << typeid(c).name() << endl;
cout << typeid(d).name() << endl;
cout << typeid(it).name() << endl;
return 0;
}
3.auto不能推导的场景
①auto不能作为函数的参数
②auto不能直接用来声明数组
三、基于范围的for循环
#include<iostream>
using namespace std;
int main()
{
//c++98
int array[] = { 1,2,3,4,5 };
for (int i = 0; i < sizeof(array) / sizeof(array[0]); ++i)
array[i] *= 2;
for (int i = 0; i < sizeof(array) / sizeof(array[0]); ++i)
cout << array[i] << " ";
cout << endl;
//c++11
// 范围for
// 依次取数组中的数据赋值给e
// 自定判断结束
// 自动迭代
for (auto e : array)
{
cout << e << " ";
}
cout << endl;
for (auto& x : array)
{
x *= 2;
}
for (auto e : array)
{
cout << e << " ";
}
cout << endl;
return 0;
}
四、面向过程和面向对象初步认识
1.C语言是面向过程的,关注的是过程,分析出求解问题的步骤,通过函数调用逐步解决问题。
2.C++是基于面向对象的,关注的是对象,将一件事情拆分成不同的对象,靠对象之间的交互完成。
五、类的引入
C
语言结构体中只能定义变量,在
C++
中,结构体内不仅可以定义变量,也可以定义函数。
比如: 在数据结构中,用C
语言方式实现的栈,结构体中只能定义变量
;现在以
C++
方式实现,
会发现
struct
中也可以定义函数。
六、类的定义
class
为
定义类的
关键字,
ClassName
为类的名字,
{}
中为类的主体,注意
类定义结束时后面
分
号不能省略
。
类体中内容称为
类的成员:
类中的
变量
称为
类的属性
或
成员变量
;
类中的
函数
称为
类的方法
或者
成员函数
。
类的两种定义方式:
1.
声明和定义全部放在类体中,需注意:成员函数如果
在类中定义
,编译器可能会将其当成
内
联函数
处理。
2. 类声明放在.h文件中,成员函数定义放在.cpp文件中,注意:成员函数名前需要加类名::
#include<iostream>
using namespace std;
class Stack
{
public:
// 成员函数
void Init()
{
a = nullptr;
top = capacity = 0;
}
void Push(int x)
{
if (top == capacity)
{
size_t newcapacity = capacity == 0 ? 4 : capacity * 2;
a = (int*)realloc(a, sizeof(int) * newcapacity);
capacity = newcapacity;
}
a[top++] = x;
}
int Top()
{
return a[top - 1];
}
private:
// 成员变量
int* a;
int top;
int capacity;
};
int main()
{
Stack st;
st.Init();
st.Push(1);
st.Push(2);
st.Push(3);
st.Push(4);
//cout << st.a[st.top-1] << endl;
cout << st.Top() << endl;
return 0;
}
七、类的访问限定符及封装
【访问限定符说明】
1. public
修饰的成员在类外可以直接被访问
2. protected
和
private
修饰的成员在类外不能直接被访问
(
此处
protected
和
private
是类似的
)
3.
访问权限
作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止
4.
如果后面没有访问限定符,作用域就到
}
即类结束。
5. class
的默认访问权限为
private
,
struct
为
public(
因为
struct
要兼容
C)
问题:C++中struct和class的区别是什么?
C++
需要兼容
C
语言,所以
C++
中
struct
可以当成结构体使用。另外
C++
中
struct
还可以用来
定义类。和
class
定义类是一样的,区别是
struct
定义的类默认访问权限是
public
,
class
定义的类
默认访问权限是
private
。注意:在继承和模板参数列表位置,
struct
和
class
也有区别,后序给大
家介绍。
面向对象的三大特性:
封装、继承、多态
。
问题:在类和对象阶段,主要是研究类的封装特性,那什么是封装呢?
封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来
和对象进行交互。
封装本质上是一种管理,让用户更方便使用类
。比如:对于电脑这样一个复杂的设备,提供给用
户的就只有开关机键、通过键盘输入,显示器,
USB
插孔等,让用户和计算机进行交互,完成日
常事务。但实际上电脑真正工作的却是
CPU
、显卡、内存等一些硬件元件。
对于计算机使用者而言,不用关心内部核心部件,比如主板上线路是如何布局的,
CPU
内部是如
何设计的等,用户只需要知道,怎么开机、怎么通过键盘和鼠标与计算机进行交互即可。因此
计
算机厂商在出厂时,在外部套上壳子,将内部实现细节隐藏起来,仅仅对外提供开关机、鼠标以
及键盘插孔等,让用户可以与计算机进行交互即可
。
在
C++
语言中实现封装,可以
通过类将数据以及操作数据的方法进行有机结合,通过访问权限来
隐藏对象内部实现细节,控制哪些方法可以在类外部直接被使用
。
八、类的实例化
#include<iostream>
using namespace std;
class Date
{
public:
void Init(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
void Print()
{
cout << _year << "/" << _month << "/" << _day << endl;
}
//private:
int _year; // 声明
int _month;
int _day;
};
int main()
{
// 定义开空间
Date d1;
d1.Init(2023, 7, 19);
d1.Print();
d1._year;
Date d2;
d2.Init(2023, 7, 19);
d2.Print();
d2._year;
cout << sizeof(Date) << endl;
cout << sizeof(d1) << endl;
return 0;
}
总结
以上就是今天要讲的内容,本文仅仅简单介绍了c++的基础知识。