2024.1.15
目录
1、 C++中,在类或结构中,成员函数与静态函数有何区别?成员字段和静态字段有何区别?
1. 有如右函数:void apply(int *array, int nn, int (*func)(int));将每个元素扩大 2 倍、和 平方 的功能,用Lambda技术实现;
上午:
1. 定义函数指针变量,进而调用函数;
void test() {
int (*pf1)(int) = two;
auto rr = pf1(11);
cout << "rr -> " << (rr) << endl;
int (*pf2)(int) =square;
rr = pf2(11);
cout << "rr -> " << (rr) << endl;
}
2. 函数指针指向成员函数和静态函数;
这里所说的成员函数,是指这些函数与类或结构有隶属关系;是与全局函数比较而言的;
1、 C++中,在类或结构中,成员函数与静态函数有何区别?成员字段和静态字段有何区别?
i. 从生活常识中解释成员和静态的概念
成员数据属于个体;静态数据属于全体;
ii. 举例:
一个Student类或结构,学号,姓名,年龄,籍贯、专业、入学分数等,这些字段或分量都是属于个人的,即是成员数据;像学生类中的教室、教员、班级编号;这些字段或函数都是属于整体的,属于所有学生的;
iii. 对于成员数据(字段和函数),需要类对象操作;
用类访问静态成员(字段和函数);
2、 为什么要抽象函数类型?解决同类函数有多个的情况;
struct Aa {
int add(int a, int b) {
return a + b;
}
void hello() {
printf("****** hello,gcc! ******\n");
}
static void print(string str) {
cout << "=> " << str << endl;
}
};
void test() {
Aa aa;
Aa *pa = new Aa;
//::称为作用域运算符;
int (Aa::*padd)(int, int) =&Aa::add;
auto rr1 = (aa.*padd)(11, 25);
cout << "rr1 -> " << (rr1) << endl;
auto rr2 = (pa->*padd)(1, 2);
cout << "rr2 -> " << (rr2) << endl;
void (*pf)(string) =&Aa::print;
pf("hello,cpp!");
pf("中国人来啦!");
}
3. 课堂练习1;
创建一个指向结构Aa成员函数hello的指针,来调用它;
struct Aa{
int add(int a, int b) {
return a + b;
}
void hello() {
printf("******,he110,gCC!*******\n”);
}
static void print(string str){
cout << "=> " << str << endl;
}
};
4. Lambda表达式的语法 1 ;
[capture list] (parameters)mutable throw() -> return-type { statement }
[capture list] [捕获列表]
(parameters) [参数列表]
mutable throw() [可变规则] 【异常说明】
-> return-type [返回类型]
{ statement } [函数体]
1、 Lambda表达式是什么?
它实际上一个匿名函数(来自于C++11版本)
2、 能干什么?
当一个函数只用一次时,就可使用匿名函数;
3、 当我们学习一个新知识点时,有时根据需要,要解决新的问题时,旧的知识点解决不了;相比旧知识解决同样的问题,代码量少,效率高;5+5+5+5+5+5 5*6
4、 对于Lambda表达式,它属于后者;
5、 四种常规函数的Lambda表示法;
i. 无参、无返回;
ii. 无参、有返回;
iii. 有参、无返回;
iv. 有参、有返回;
6、 Lambda表达式之HelloWorld;
void test() {
int b = 10; //局部变量
//创建一个匿名函数实现三数和的功能
/*auto add = [](int i, float f, double d) {
cout << "*** 三数之和 ***" << endl;
return i + f + d;
};
auto rr1 = add(10, 3.45f, 3.1415);
cout << "rr1 -> " << (rr1) << endl;*/
/*auto rr = [](int i, float f, double d) {
cout << "*** 三数之和 ***" << endl;
return i + f + d;
}(10, 3.45f, 3.1415);
cout << "rr -> " << (rr) << endl;*/
cout << "rr -> " << [](int i, float f, double d) {
cout << "*** 三数之和 ***" << endl;
return i + f + d;
}(10, 3.45f, 3.1415) << endl;
}
第三个版本的Lambda表达式,是将函数的:声明、定义、调用三者于一体;
7. 没有参数的Lambda表达式;当一个匿名函数没有参数时,小括号可以省略;
void hello();
int get();
void test() {
auto af = []() {
cout << "*** hello! ***" << endl;
};
af();
auto bf = [] {
return 120;
};
cout << " bf() -> " << [] {
return 120;
}() << endl;
af();
}
5. 课堂练习2;
1. 有如右函数:void apply(int *array, int nn, int (*func)(int));将每个元素扩大 2 倍、和 平方 的功能,用Lambda技术实现;
void apply(int *array, int nn, int (*func)(int));
void showIntegerArray(int *aa, int nn);
void test() {
int aa[]{11, 2, 3, 100, 55,};
int nn = sizeof aa / sizeof *aa;
showIntegerArray(aa, nn);
printf("\n");
//如何将扩大2倍的功能用Lambda表达式实现
apply(aa, nn, [](int elem) {
return elem * 2;
});
showIntegerArray(aa, nn);
//如何将元素平方的功能用Lambda表达式实现
apply(aa, nn, [](int elem) {
return elem * elem;
});
showIntegerArray(aa, nn);
}
void showIntegerArray(int *aa, int nn) {
if (!aa || nn < 1)
return;
for (int i = 0; i < nn; ++i) {
cout << setw(10) << aa[i];
}
printf("\n");
}
void apply(int *array, int nn, int (*func)(int)) {
if (!array || nn < 1) {
return;
}
for (int i = 0; i < nn; ++i) {
array[i] = func(array[i]);
}
}
2. 基于一维整型数组的 << 运算符重载;
#include <iostream>
#include <cstring> //表示C语言中的string.h
#include <string> //C++中的string类
#include <iomanip>
using namespace std;
//基于整型一维数组的 << 运算符重载
template<int N>
ostream &operator<<(ostream &out, const int (&raa)[N]) {
if (!raa || N < 1) {
return out;
}
for (int i = 0; i < N; ++i) {
out << setw(5) << raa[i];
}
out << endl;
return out;
}
void test();
int main(int argc, char *argv[]) {
test();
return 0;
}
struct Aa {
int id;
char name[40];
friend ostream &operator<<(ostream &out, const Aa &obj) {
return out << "{" << obj.id << "," << obj.name << "}";
}
};
void test() {
double pi = 3.14159; //内置类型
cout << pi << endl;
printf("\n");
Aa aa{1024, "张三 xiao ming"}; //结构对象
cout << aa << endl;
printf("\n");
int array[]{11, 2, 3, 100, 55, 78, 87,};// 数组
cout << array << endl;
double dd[]{3.14159, 2.71828, 0.618,};
cout << dd << endl;
}
6. 课堂练习3;
依照一维整型的输出运算符重载实现代码,将对于一维双精度类型的数组,进行重载;以便于对实型数组用cout << dd << endl; 进行遍历;
//基于实型一维数组的 << 运算符重载
template<int N>
ostream &operator<<(ostream &out, const double (&raa)[N]) {
if (!raa || N < 1) {
return out;
}
for (int i = 0; i < N; ++i) {
printf("%10lg", raa[i]);
}
printf("\n");
return out;
}
void test() {
double pi = 3.14159; //内置类型
cout << pi << endl;
printf("\n");
Aa aa{1024, "张三 xiao ming"}; //结构对象
cout << aa << endl;
printf("\n");
int array[]{11, 2, 3, 100, 55, 78, 87,};// 数组
cout << array << endl;
double dd[]{3.14159, 2.71828, 0.618,};
cout << dd << endl;
}
7. C++中的引用概念
1、 在C++语言,有些概念是C++语言所特有的;
比如:运算符重载,引用;
2、 何为引用?
引用就是变量的别名,相当于作家的笔名;作家的本名和别名,都是代表作家本人;最著名的笔名就是鲁迅,鲁迅和周树人两个名字表示一个人;
3、 引用的用途?
在C++中,引用的重要仅次于指针! 在很多情况下,引用使用更多;用引用代替指针,用法更直观;
4、 引用和指针的比较?
指针指变量的地址;引用是变量的别名;
5、 在C语言和C++中,有一个典型的例子:两数交换;
i. 在C语言中,通过指针完成两数交换;
ii. 在C++中,既可通过指针,也可以通过引用;
iii. 在C++中,既可通过指针,完成类的多态操作;也可通过引用,完成类的多态操作;
6、 三类函数;同一范围(同一个文档或同一个类);
i. 重载;函数名相同,参数列表不同;只须符合下面一条就是重载;
1. 参数个数不同;
2. 个数相同,类型不同;
3. 个数同,类型同,顺序不同;
void hello(); int hello(); ×
void hello(); int hello(double); √
int hello(int a,int b); void hello(int a,int b,int c); √
void hello(int a,double d); double hello(double d,int a); √
void change(int *p1, int *p2) {
int tt = *p1;
*p1 = *p2;
*p2 = tt;
}
void change(int &ref1, int &ref2) {
int tt = ref1;
ref1 = ref2;
ref2 = tt;
}
void change(int *p1, int *p2);
void change(int &ref1, int &ref2);
void test() {
printf("\n");
auto a = 145;
auto b = 3000;
cout << "a -> " << (a) << endl;
cout << "b -> " << (b) << endl;
printf("\n");
change(&a, &b);
cout << "a -> " << (a) << endl;
cout << "b -> " << (b) << endl;
printf("\n");
change(a,b);
cout << "a -> " << (a) << endl;
cout << "b -> " << (b) << endl;
}
void change(int *p1, int *p2) {
int tt = *p1; //tt:145
*p1 = *p2; //a=3000
*p2 = tt; //b=145
}
void change(int &ref1, int &ref2) {
int tt = ref1;
ref1 = ref2;
ref2 = tt;
}
ii. 重写;出现在继承链上的多态中,父类和子类;在子类中重写从父类中继承来的函数;在C++中,父类中的那个方法和子类中的继承来的方法,函数原型完全相同;
struct A {
virtual void aa() {
cout << "*** A::aa() ***" << endl;
}
};
struct B : public A {
void aa() {
cout << "*** B::aa() ***" << endl;
}
};
父类: virtual void aa();
子类;void aa();
class Aa {
public:
virtual void aa() { //虚函数,标明这个函数可以在子类中重写
cout << "*** A::aa() ***" << endl;
}
};
class Bb : public Aa {
public:
void aa() {
cout << "*** B::aa() ***" << endl;
}
};
//用父类型的指针或引用来调用子类中从父类中继承来的方法;
void test() {
Aa aa;
Bb bb;
aa.aa();
bb.aa();
printf("\n");
Aa &ra = bb; //ra就是bb的别名;父类型的引用调用子类的方法;
ra.aa();
printf("\n");
Aa *pa = &bb;
pa->aa();
printf("\n");
Aa *pb = new Bb();
pb->aa();
delete pb;
pb = nullptr;
}
iii. 同类;返回值类型相同,参数列表相同,函数名不同;变量|类型;
8. 自定义头文件;
1、 C++中的头文件有两类
一是预定义的头文件,如iostream,stdio,time,math等;
还有一类就是自定义的头文件;
2、 自定义头文件包含什么东西?
i. 预定义头文件;
ii. 通用的辅助性的自定义的函数;
iii. 针对某些数据类型重载的运算符;
3、 自定义头文件示例
gaoming.hpp
#ifndef CPP17_GAOMING_HPP
#define CPP17_GAOMING_HPP
#include <iostream>
#include <cstring>
#include <string>
#include <iomanip>
#include <cstdio>
using namespace std;//基于整型一维数组的 << 运算符重载
template<int N>
ostream &operator<<(ostream &out, const int (&raa)[N]) {
if (!raa || N < 1) {
return out;
}
for (int i = 0; i < N; ++i) {
out << setw(5) << raa[i];
}
printf("\n");
return out;
}
//基于实型一维数组的 << 运算符重载
template<int N>
ostream &operator<<(ostream &out, const double (&raa)[N]) {
if (!raa || N < 1) {
return out;
}
for (int i = 0; i < N; ++i) {
printf("%10lg", raa[i]);
}
printf("\n");
return out;
}
#endif
应用自定义头文件时,只须将其包含到main函数所在源文件中即可;
9. Lambda表达式的语法 2 ;
1、 常规的匿名函数;无参和带参的;
i. 先生成匿名函数;
ii. 调用匿名函数得到结果;
iii. 输出匿名函数的调用结果;
2、 捕获列表能够捕获什么东西?何为捕获?就是使用;
i. 全局变量;
ii. 局部变量;
int gg = 10; //全局变量;
void test() {
cout << "gg -> " << (gg) << endl;
int hh = 100; //局部变量
int ii = 10;
auto af = [ii, hh] { //只读捕获
gg++;
return gg + hh * ii;
};
auto rr1 = af();
cout << "rr1 -> " << (rr1) << endl;
cout << "gg -> " << (gg) << endl;
printf("\n");
auto bf = [&ii, &hh] { //可读写捕获
ii *= 10;
hh /= 10;
gg /= 5;
return gg + hh + ii;
};
auto rr2 = bf();
cout << "rr2 -> " << (rr2) << endl;
cout << "gg -> " << (gg) << endl;
cout << "ii -> " << (ii) << endl;
cout << "hh -> " << (hh) << endl;
printf("\n");
//两个局部变量,一可读,一不可改;
auto cf = [ii, &hh] { //ii只读,hh可读写
hh++;
return ii * hh;
};
auto rr3 = cf();
cout << "rr3 -> " << (rr3) << endl;
printf("\n");
//如果说所有局部变量都不可改,捕获列表用 = 表示;
auto df = [=] {
/*ii++;
++hh;*/
return ii + hh;
};
auto rr4 = df();
cout << "rr4 -> " << (rr4) << endl;
printf("\n");
//如果说所有局部变量都可读写,捕获列表用 & 表示;
auto ef = [&] {
ii++;
--hh;
return ii - hh;
};
auto rr5 = ef();
cout << "rr5 -> " << (rr5) << endl;
printf("\n");
/*
* 如有100个局部变量,99个可改,1个不可改;ii,hh
*/
auto jj = 3;
auto ff = [&, jj] {
++ii;
hh--;
//++jj;
return ii + hh + jj;
};
auto rr6 = ff();
cout << "rr6 -> " << (rr6) << endl;
printf("\n");
auto gf = [=, &jj] {
jj *= 10;
/*++ii;
hh--;*/
return ii + hh * jj;
};
auto rr7 = gf();
cout << "rr7 -> " << (rr7) << endl;
printf("\n");
auto hf = [=](int a, int b) {
//jj++;
return a * b + (ii + hh + jj);
};
auto rr8 = hf(10, 20);
cout << "rr8 -> " << (rr8) << endl;
}
10.课堂练习4;
将两个整数的操作,如int add(int,int); int sub(int,int); int times(int,int); 因为是同类函数,设计用Lambda表达式实现匿名函数,将三个函数放在一个数组,循环调用,得到结果;
1、 同类函数;
2、 抽象出某类函数的数据类型;
3、 三个作为匿名函数出现;
4、 数组操作;
5、 遍历数组,调用每个匿名函数;
第一个版本;
void test() {
typedef int (*ptrFunction)(int, int);
auto a = 1450;
auto b = 1000;
cout << "a -> " << (a) << endl;
cout << "b -> " << (b) << endl;
printf("\n");
auto af = [](int e1, int e2) {
return e1 + e2;
};
auto bf = [](int e1, int e2) {
return e1 - e2;
};
auto cf = [](int e1, int e2) {
return e1 * e2;
};
auto df = [](int e1, int e2) {
return e1 / e2;
};
ptrFunction functions[]{af, bf, cf, df,};
//int nn = sizeof functions / sizeof *functions;
for (int i = 0, nn = sizeof functions / sizeof *functions; i < nn; ++i) {
auto func = functions[i];
auto rr = func(a, b);
cout << "=> " << rr << endl;
}
}
第二个版本;
void test() {
typedef int (*ptrFunction)(int, int);
auto a = 1450;
auto b = 1000;
cout << "a -> " << (a) << endl;
cout << "b -> " << (b) << endl;
printf("\n");
ptrFunction functions[]{[](int e1, int e2) {
return e1 + e2;
}, [](int e1, int e2) {
return e1 - e2;
}, [](int e1, int e2) {
return e1 * e2;
}, [](int e1, int e2) {
return e1 / e2;
},};
for (int i = 0, nn = sizeof functions / sizeof *functions; i < nn; ++i) {
cout << "=> " << functions[i](a, b) << endl;
}
}