入门学习逆向的个人笔记,预览(欢迎探讨)
[原创] [calleng的逆向日记] 22y11m-23y3m29d 实现macOS编辑, iOS端编译和调试C/C++
[原创] [calleng的逆向日记] 23/03/30 (C++概念构建篇01) 补充完毕
[分享] [calleng的逆向日记] 22y11m-23y6m7d Win10Arm下的 gdb调试.[数据结构/严蔚敏-之迷宫问题]
[分享] IOS软件安全工程师技能表(2017.7by非虫) (为自己学习导航) 图片不清楚下面有导图下载
[分享] Frida-Tool的一些 介绍, 和在 iOS下的一些用法 [个人笔记汇总]
[原创] [calleng的逆向日记] 弹窗的修改原理-OC篇 [源码学习和HOOK实践]23/09/24 --待续
[讨论] [calleng的逆向日记] 自学iOS逆向时候,如何自己解决问题.
[分享] [calleng逆向日记] iOS crackMe的破解 与 Frida(Objection) 的入门使用(thanks to roysue)
[分享] (iOS Hook原理,OC底层实现)Frida前置知识的(royuse)的一些知识注解(图片三次压缩失真,详情见附件)
[原创] (calleng逆向日记)Frida前置知识, ObjC runtime的"反射"-KVC-实例代码理解和分析
[分享] [calleng的逆向日记] Frida 前置知识, 类与方法的底层实现, 逻辑批注, (参考AloneMonkey的书)
[原创] (calleng逆向日记)Frida前置知识, ObjC runtime的"反射" KVC实例Demo分析第二部(Demo底部下载)
[分享] [calleng的逆向日记] iOS crackMe and Frida(Objection) Get Started (Oct,16th)
[分享] [calleng的逆向日记] Frida在iOS上内存漫游与黑盒调用 Get Started Section 4
占坑,12点后再补充
目前购买了董洪伟老师的C++17从入门到精通, book 包含了12个章节,
✅ 1, C++基础
✅ 2, 变量和类型
✅ 3,运算符号和表达式
✅ 4,语句
✅ 5,复合类型:数组,指针和引用
✅ 6,函数
✅ 7,类和对象
✅ 8,运算符重载
✅ 9,派生类
✅ 10,模版
✅ 11,移动语义
❌ 12,函数指针,函数对象, Lambda表达式
❌ 13,C++标准库介绍
❌ 14,异常处理
✅ 代表学习完成,
❌ 代表即将学习.
之前学习 Objective-C的时候, 花了1000 rmb 的课程, 1080p的课程给我搞成了, 480p糊的画面, 腾讯课堂话说无果. 看来只能投诉在工信部投诉他们.
于是对腾讯课堂买课不敢恭维,所以就 只要没有1080p的课都是 LJ, 所以,找到了
董老师的 6小时掌握 c 语言1080p,学习后真是享受,后来发现了他出了C++的课程,PPT都写好发布出来,所以买了book.
后来 买了 编程网的 永久会员. 所以, 当作C++的补充资料.
类和对象
2.13 static静态成员函数详解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | using namespace std;
class Student{
public:
Student(char * name, int age, float score);
void show();
public: / / 声明静态成员函数
static int getTotal();
static float getPoints();
private:
static int m_total; / / 总人数
static float m_points; / / 总成绩
private:
char * m_name;
int m_age;
float m_score;
};
int Student::m_total = 0 ;
float Student::m_points = 0.0 ;
Student::Student(char * name, int age, float score): m_name(name), m_age(age), m_score(score){
m_total + + ;
m_points + = score;
}
void Student::show(){
cout<<m_name<< "的年龄是" <<m_age<< ",成绩是" <<m_score<<endl;
}
/ / 定义静态成员函数
int Student::getTotal(){
return m_total;
}
float Student::getPoints(){
return m_points;
}
int main(){
(new Student( "小明" , 15 , 90.6 )) - > show();
(new Student( "李磊" , 16 , 80.5 )) - > show();
(new Student( "张华" , 16 , 99.0 )) - > show();
(new Student( "王康" , 14 , 60.8 )) - > show();
int total = Student::getTotal();
float points = Student::getPoints();
cout<< "当前共有" <<total<< "名学生,总成绩是" <<points<< ",平均分是" <<points / total<<endl;
return 0 ;
}
|
2.14 const成员变量,成员函数(常成员函数)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | class Student{
public:
Student(char * name, int age, float score);
void show();
/ / 声明常成员函数
char * getname() const;
int getage() const;
float getscore() const;
private:
char * m_name;
int m_age;
float m_score;
};
Student::Student(char * name, int age, float score): m_name(name), m_age(age), m_score(score){ }
void Student::show(){
cout<<m_name<< "的年龄是" <<m_age<< ",成绩是" <<m_score<<endl;
}
/ / 定义常成员函数
char * Student::getname() const{
return m_name;
}
int Student::getage() const{
return m_age;
}
float Student::getscore() const{
return m_score;
}
|
###2.15 const对象(常对象)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | using namespace std;
class Student{
public:
Student(char * name, int age, float score);
public:
void show();
char * getname() const;
int getage() const;
float getscore() const;
private:
char * m_name;
int m_age;
float m_score;
};
Student::Student(char * name, int age, float score): m_name(name), m_age(age), m_score(score){ }
void Student::show(){
cout<<m_name<< "的年龄是" <<m_age<< ",成绩是" <<m_score<<endl;
}
char * Student::getname() const{
return m_name;
}
int Student::getage() const{
return m_age;
}
float Student::getscore() const{
return m_score;
}
int main(){
const Student stu( "小明" , 15 , 90.6 );
/ / stu.show(); / / error
cout<<stu.getname()<< "的年龄是" <<stu.getage()<< ",成绩是" <<stu.getscore()<<endl;
const Student * pstu = new Student( "李磊" , 16 , 80.5 );
/ / pstu - > show(); / / error
cout<<pstu - >getname()<< "的年龄是" <<pstu - >getage()<< ",成绩是" <<pstu - >getscore()<<endl;
return 0 ;
}
|
2.16 友元函数和友元类(friend关键字)
1) 将非成员函数声明为友元函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | using namespace std;
class Student{
public:
Student(char * name, int age, float score);
public:
friend void show(Student * pstu); / / 将show()声明为友元函数
private:
char * m_name;
int m_age;
float m_score;
};
Student::Student(char * name, int age, float score): m_name(name), m_age(age), m_score(score){ }
/ / 非成员函数
void show(Student * pstu){
cout<<pstu - >m_name<< "的年龄是 " <<pstu - >m_age<< ",成绩是 " <<pstu - >m_score<<endl;
}
int main(){
Student stu( "小明" , 15 , 90.6 );
show(&stu); / / 调用友元函数
Student * pstu = new Student( "李磊" , 16 , 80.5 );
show(pstu); / / 调用友元函数
return 0 ;
}
|
2) 将其他类的成员函数声明为友元函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | using namespace std;
class Address; / / 提前声明Address类
/ / 声明Student类
class Student{
public:
Student(char * name, int age, float score);
public:
void show(Address * addr);
private:
char * m_name;
int m_age;
float m_score;
};
/ / 声明Address类
class Address{
private:
char * m_province; / / 省份
char * m_city; / / 城市
char * m_district; / / 区(市区)
public:
Address(char * province, char * city, char * district);
/ / 将Student类中的成员函数show()声明为友元函数
friend void Student::show(Address * addr);
};
/ / 实现Student类
Student::Student(char * name, int age, float score): m_name(name), m_age(age), m_score(score){ }
void Student::show(Address * addr){
cout<<m_name<< "的年龄是 " <<m_age<< ",成绩是 " <<m_score<<endl;
cout<< "家庭住址:" <<addr - >m_province<< "省" <<addr - >m_city<< "市" <<addr - >m_district<< "区" <<endl;
}
/ / 实现Address类
Address::Address(char * province, char * city, char * district){
m_province = province;
m_city = city;
m_district = district;
}
int main(){
Student stu( "小明" , 16 , 95.5f );
Address addr( "陕西" , "西安" , "雁塔" );
stu.show(&addr);
Student * pstu = new Student( "李磊" , 16 , 80.5 );
Address * paddr = new Address( "河北" , "衡水" , "桃城" );
pstu - > show(paddr);
return 0 ;
}
|
3) 友元类
- 不仅可以将一个函数声明为一个类的“朋友”,还可以将整个类声明为另一个类的“朋友”,这就是友元类。友元类中的所有成员函数都是另外一个类的友元函数。
- 例如将类 B 声明为类 A 的友元类,那么类 B 中的所有成员函数都是类 A 的友元函数,可以访问类 A 的所有成员,包括 public、protected、private 属性的。
- 更改上例的代码,将 Student 类声明为 Address 类的友元类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | using namespace std;
class Address; / / 提前声明Address类
/ / 声明Student类
class Student{
public:
Student(char * name, int age, float score);
public:
void show(Address * addr);
private:
char * m_name;
int m_age;
float m_score;
};
/ / 声明Address类
class Address{
public:
Address(char * province, char * city, char * district);
public:
/ / 将Student类声明为Address类的友元类
friend class Student;
private:
char * m_province; / / 省份
char * m_city; / / 城市
char * m_district; / / 区(市区)
};
/ / 实现Student类
Student::Student(char * name, int age, float score): m_name(name), m_age(age), m_score(score){ }
void Student::show(Address * addr){
cout<<m_name<< "的年龄是 " <<m_age<< ",成绩是 " <<m_score<<endl;
cout<< "家庭住址:" <<addr - >m_province<< "省" <<addr - >m_city<< "市" <<addr - >m_district<< "区" <<endl;
}
/ / 实现Address类
Address::Address(char * province, char * city, char * district){
m_province = province;
m_city = city;
m_district = district;
}
int main(){
Student stu( "小明" , 16 , 95.5f );
Address addr( "陕西" , "西安" , "雁塔" );
stu.show(&addr);
Student * pstu = new Student( "李磊" , 16 , 80.5 );
Address * paddr = new Address( "河北" , "衡水" , "桃城" );
pstu - > show(paddr);
return 0 ;
}
|
2.17类其实也是一种作用域
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | using namespace std;
class A{
public:
typedef int INT ;
static void show();
void work();
};
void A::show(){ cout<< "show()" <<endl; }
void A::work(){ cout<< "work()" <<endl; }
int main(){
A a;
a.work(); / / 通过对象访问普通成员
a.show(); / / 通过对象访问静态成员
A::show(); / / 通过类访问静态成员
A:: INT n = 10 ; / / 通过类访问 typedef 定义的类型
return 0 ;
}
|
####定义在类外部的成员
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | using namespace std;
class A{
public:
typedef char * PCHAR;
public:
void show(PCHAR str );
private:
int n;
};
void A::show(PCHAR str ){
cout<< str <<endl;
n = 10 ;
}
/ / A::PCHAR A::show(PCHAR str ){
/ / cout<< str <<endl;
/ / n = 10 ;
/ / return str ;
/ / }
int main(){
A obj;
obj.show( "http://c.biancheng.net" );
return 0 ;
}
|
2.18 class和struct到底有什么区别
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | using namespace std;
struct Student{
Student(char * name, int age, float score);
void show();
char * m_name;
int m_age;
float m_score;
};
Student::Student(char * name, int age, float score): m_name(name), m_age(age), m_score(score){ }
void Student::show(){
cout<<m_name<< "的年龄是" <<m_age<< ",成绩是" <<m_score<<endl;
}
int main(){
Student stu( "小明" , 15 , 92.5f );
stu.show();
Student * pstu = new Student( "李华" , 16 , 96 );
pstu - > show();
return 0 ;
}
|
2.19 string详解,C++字符串详解-
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | using namespace std;
int main(){
string s1;
string s2 = "c plus plus" ;
string s3 = s2;
string s4 ( 5 , 's' );
string s = "http://c.biancheng.net" ;
int len = s.length();
cout<< len <<endl;
cout<<s1.length()<<endl;
cout<<s2.length()<<endl;
cout<<s3.length()<<endl;
cout<<s4.length()<<endl;
}
|
2.19 string详解,字符串详解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | using namespace std;
int main(){
string s1;
string s2 = "c plus plus" ;
string s3 = s2;
string s4 ( 5 , 's' );
string s = "http://c.biancheng.net" ;
int len = s.length();
cout<< len <<endl;
cout<<s1.length()<<endl;
cout<<s2.length()<<endl;
cout<<s3.length()<<endl;
cout<<s4.length()<<endl;
}
|
string 字符串的输入输出
1 2 3 4 5 6 7 8 9 | using namespace std;
int main(){
string s;
cin>>s; / / 输入字符串
cout<<s<<endl; / / 输出字符串
return 0 ;
}
|
访问字符串中的字符
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | using namespace std;
int main(){
string s = "i like my father and my mother!" ,s3;
for ( int i = 0 , len = s.length(); i< len ; i + + ){
cout<<s[i]<< " " ;
}
cout<<endl;
s3 = "拼" ;
s.insert( 5 ,s3);
cout<<s<<endl;
return 0 ;
}
|
字符串的拼接
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | using namespace std;
int main(){
string s1 = "first " ;
string s2 = "second " ;
char * s3 = "third " ;
char s4[] = "fourth " ;
char ch = '@' ;
string s5 = s1 + s2;
string s6 = s1 + s3;
string s7 = s1 + s4;
string s8 = s1 + ch;
cout<<s5<<endl<<s6<<endl<<s7<<endl<<s8<<endl;
return 0 ;
}
|
string 字符串的增删改查,一. 插入字符串
1 2 3 4 5 6 7 8 9 10 11 12 13 | using namespace std;
int main(){
string s1, s2, s3;
s1 = s2 = "1234567890" ;
s3 = "aaa" ;
s1.insert( 5 , s3);
cout<< s1 <<endl;
s2.insert( 7 , "bbb" );
cout<< s2 <<endl;
return 0 ;
}
|
string 字符串的增删改查,二. 删除字符串
1 2 3 4 5 6 7 8 9 10 11 12 13 | using namespace std;
int main(){
string s1, s2, s3;
s1 = s2 = s3 = "1234567890" ;
s2.erase( 5 );
s3.erase( 5 , 3 );
cout<< s1 <<endl;
cout<< s2 <<endl;
cout<< s3 <<endl;
return 0 ;
}
|
string 字符串的增删改查,三. 提取子字符串
1 2 3 4 5 6 7 8 9 10 11 | using namespace std;
int main(){
string s1 = "first second third" ;
string s2;
s2 = s1.substr( 6 , 6 );
cout<< s1 <<endl;
cout<< s2 <<endl;
return 0 ;
}
|
string 字符串的增删改查,四. 字符串查找
1 2 3 4 5 6 7 8 9 10 11 12 13 | using namespace std;
int main(){
string s1 = "first second third" ;
string s2 = "second" ;
int index = s1.find(s2, 5 ); / / 第一个参数为待查找的子字符串。第二个参数为开始查找的位置(下标);如果不指明,则从第 0 个字符开始查找。
if (index < s1.length())
cout<< "Found at index : " << index <<endl;
else
cout<< "Not found" <<endl;
return 0 ;
}
|
string 字符串的增删改查, 四. 字符串查找 2) rfind() 函数
不同的是 find() 函数从第二个参数开始往后查找,而 rfind() 函数则最多查找到第二个参数处
1 2 3 4 5 6 7 8 9 10 11 12 13 | using namespace std;
int main(){
string s1 = "first second third" ;
string s2 = "second" ;
int index = s1.rfind(s2, 6 ); / / 而 rfind() 函数则最多查找到第二个参数处
if (index < s1.length())
cout<< "Found at index : " << index <<endl;
else
cout<< "Not found" <<endl;
return 0 ;
}
|
C++引用
C++引用10分钟入门
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | / *
* C + + 引用 10 分钟入门教程
* 引用可以看做是数据的一个别名,通过这个别名和原来的名字都能够找到这份数据
* 引用必须在定义的同时初始化,并且以后也要从一而终,不能再引用其它数据,这有点类似于常量(const 变量)。
* /
using namespace std;
int main() {
int a = 99 ;
int &r = a;
cout << a << ", " << r << endl;
cout << &a << ", " << &r << endl;
return 0 ;
}
/ *
* 注意,引用在定义时需要添加&,在使用时不能添加&,使用时添加&表示取地址
* 由于引用 r 和原始变量 a 都是指向同一地址,所以通过引用也可以修改原始变量中所存储的数据,请看下面的例子:
* 如果读者不希望通过引用来修改原始的数据,那么可以在定义时添加 const 限制,形式为:const type &name = value;
* /
using namespace std;
int main() {
int a = 99 ;
int &r = a;
r = 47 ;
cout << a << ", " << r << endl;
return 0 ;
}
/ *
* 一个能够展现按引用传参的优势的例子就是交换两个数的值,请看下面的代码:
* /
using namespace std;
void swap1( int a, int b);
void swap2( int * p1, int * p2);
void swap3( int &r1, int &r2);
int main() {
int num1, num2;
cout << "Input two integers: " ;
cin >> num1 >> num2;
swap1(num1, num2);
cout << num1 << " " << num2 << endl;
cout << "Input two integers: " ;
cin >> num1 >> num2;
swap2(&num1, &num2);
cout << num1 << " " << num2 << endl;
cout << "Input two integers: " ;
cin >> num1 >> num2;
swap3(num1, num2);
cout << num1 << " " << num2 << endl;
return 0 ;
}
/ / 直接传递参数内容
void swap1( int a, int b) {
int temp = a;
a = b;
b = temp;
}
/ / 传递指针
void swap2( int * p1, int * p2) {
int temp = * p1;
* p1 = * p2;
* p2 = temp;
}
/ / 按引用传参
void swap3( int &r1, int &r2) {
int temp = r1;
r1 = r2;
r2 = temp;
}
|
引用作为函数返回值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 | / * C + + 引用作为函数返回值
* 引用除了可以作为函数形参,还可以作为函数返回值
* 在将引用作为函数返回值时应该注意一个小问题,就是不能返回局部数据(例如局部变量、局部对象、局部数组等)的引用,
* 因为当函数调用完成后局部数据就会被销毁,有可能在下次使用时数据就不存在了,C + + 编译器检测到该行为时也会给出警告。
* /
using namespace std;
int &plus10( int &r) {
r + = 10 ;
return r;
}
int main() {
int num1 = 10 ;
int num2 = plus10(num1);
cout << num1 << " " << num2 << endl;
return 0 ;
}
/ *
* 更改上面的例子,让 plus10() 返回一个局部数据的引用:
* /
using namespace std;
int &plus10( int &r) {
int m = r + 10 ;
return m; / / 返回局部数据的引用
}
int main() {
int num1 = 10 ;
int num2 = plus10(num1); / / 20
cout << num2 << endl;
int &num3 = plus10(num1); / / 30
int &num4 = plus10(num3); / / 20
cout << num3 << " " << num4 << endl;
return 0 ;
}
/ *
* C + + 引用在本质上是什么,它和指针到底有什么区别?
* /
using namespace std;
int main(){
int a = 99 ;
int &r = a;
cout<<a<< ", " <<r<<endl;
cout<<&a<< ", " <<&r<<endl;
return 0 ;
}
/ *
* 成员变量 r 是 private 属性的,不能直接通过对象来访问,
* 但是借助强大的指针和类型转换,我们依然可以得到它的内容,
* 只不过这种方法有点蹩脚,我们将在《突破访问权限的限制(C + + Hack)》一节中详细阐述,读者暂时不必理解,
* 只要知道第 20 行代码是用来输出 r 本身的内容的即可。
* /
using namespace std;
int num = 99 ;
class A{
public:
A();
private:
int n;
int &r;
};
A::A(): n( 0 ), r(num){}
int main (){
A * a = new A();
cout<<sizeof(A)<<endl; / / 输出A类型的大小
cout<< hex <<showbase<< * (( int * )a + 1 )<<endl; / / 输出r本身的内容 ||代码中, hex 表示以十六进制输出,showbase表示添加十六进制前缀 0x 。
cout<<&num<<endl; / / 输出num变量的地址
return 0 ;
}
/ * 从运行结果可以看出:
* 成员变量 r 是占用内存的,如果不占用的话,sizeof(A)的结果应该为 16 。
* r 存储的内容是 0xb0000000 ,也即变量 num 的地址 0x100434060 。
*
* 其实引用只是对指针进行了简单的封装,它的底层依然是通过指针实现的,
* 引用占用的内存和指针占用的内存长度一样,
* 在 32 位环境下是 4 个字节,在 64 位环境下是 8 个字节,在iOS系统下,字节对齐所以 16 个字节
*
* 之所以不能获取引用的地址,是因为编译器进行了内部转换
*
* 使用&r取地址时,编译器会对代码进行隐式的转换,使得代码输出的是 r 的内容(a 的地址),而不是 r 的地址,
* 这就是为什么获取不到引用变量的地址的原因。也就是说,不是变量 r 不占用内存,而是编译器不让获取它的地址。
*
* 引用虽然是基于指针实现的,但它比指针更加易用,从上面的两个例子也可以看出来,通过指针获取数据时需要加 * ,书写麻烦,而引用不需要,它和普通变量的使用方式一样。
* C + + 的发明人 Bjarne Stroustrup 也说过,他在 C + + 中引入引用的直接目的是为了让代码的书写更加漂亮,尤其是在运算符重载中,不借助引用有时候会使得运算符的使用很麻烦。
* /
|
引用和指针的其他区别
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | / *
* 引用和指针的其他区别
*
* 1 ) 引用必须在定义时初始化,并且以后也要从一而终,不能再指向其他数据
* 2 ) 可以有 const 指针,但是没有 const 引用。
* 3 ) 指针可以有多级,但是引用只能有一级
* 4 ) 指针和引用的自增( + + )自减( - - )运算意义不一样。对指针使用 + + 表示指向下一份数据,对引用使用 + + 表示它所指代的数据本身加 1 ;自减( - - )也是类似的道理。
* /
using namespace std;
int main (){
int a = 10 ;
int &r = a;
r + + ; / / 对引用使用 + + 表示它所指代的数据本身加 1
cout<<r<<endl;
int arr[ 2 ] = { 27 , 84 };
int * p = arr;
p + + ;
cout<< * p<<endl; / / 对指针使用 + + 表示指向下一份数据
return 0 ;
}
|
引用不能绑定到临时数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | / *
* C + + 引用不能绑定到临时数据
* /
using namespace std;
typedef struct{
int a;
int b;
} S;
/ / 这里用到了一点新知识,叫做运算符重载,我们会在《运算符重载》一章中详细讲解
S operator + (const S &A, const S &B){
S C;
C.a = A.a + B.a;
C.b = A.b + B.b;
return C;
}
S func(){
S a;
a.a = 100 ;
a.b = 200 ;
return a;
}
int main(){
S s1 = { 23 , 45 };
S s2 = { 90 , 75 };
S * p1 = &(s1 + s2);
S * p2 = &(func());
cout<<p1<< ", " <<p2<<endl;
return 0 ;
}
/ *
* 引用也不能指代临时数据
* /
typedef struct{
int a;
int b;
} S;
int func_int(){
int n = 100 ;
return n;
}
S func_s(){
S a;
a.a = 100 ;
a.b = 200 ;
return a;
}
/ / 这里用到了一点新知识,叫做运算符重载,我们会在《运算符重载》一章中详细讲解
S operator + (const S &A, const S &B){
S C;
C.a = A.a + B.a;
C.b = A.b + B.b;
return C;
}
int main(){
/ / 下面的代码在GCC和Visual C + + 下都是错误的
int m = 100 , n = 36 ; / / 第 28 ~ 33 行代码在 GCC 和 Visual C + + 下都不能编译通过
int &r1 = m + n; / / 第 28 ~ 33 行代码在 GCC 和 Visual C + + 下都不能编译通过
int &r2 = m + 28 ; / / 第 28 ~ 33 行代码在 GCC 和 Visual C + + 下都不能编译通过
int &r3 = 12 * 3 ; / / 第 28 ~ 33 行代码在 GCC 和 Visual C + + 下都不能编译通过
int &r4 = 50 ; / / 第 28 ~ 33 行代码在 GCC 和 Visual C + + 下都不能编译通过
int &r5 = func_int(); / / 第 28 ~ 33 行代码在 GCC 和 Visual C + + 下都不能编译通过
/ / 下面的代码在GCC下是错误的,在Visual C + + 下是正确的
S s1 = { 23 , 45 }; / / 第 38 ~ 39 行代码在 Visual C + + 下能够编译通过,但是在 GCC 下编译失败。
S s2 = { 90 , 75 }; / / 第 38 ~ 39 行代码在 Visual C + + 下能够编译通过,但是在 GCC 下编译失败。
S &r6 = func_s();
S &r7 = s1 + s2;
return 0 ; / *
* 在 GCC 下,引用不能指代任何临时数据,不管它保存到哪里;
* 在 Visual C + + 下,引用只能指代位于内存中(非代码区)的临时数据,不能指代寄存器中的临时数据。
*
* 关于常量表达式
* 诸如 100 、 200 + 34 、 34.5 * 23 、 3 + 7 / 3 等不包含变量的表达式称为常量表达式(Constant expression)。
* 总起来说,常量表达式的值虽然在内存中,但是没有办法寻址,所以也不能使用&来获取它的地址,更不能用指针指向它。
* isOdd() 函数用来判断一个数是否为奇数,它的参数是引用类型,只能传递变量,不能传递常量或者表达式。
* /
}
|
编译器会为const引用创建临时变量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | / *
* - - - - - - - - 3.4 - - - - - 编译器会为const引用创建临时变量 - - - - - - - - -
* /
typedef struct{
int a;
int b;
} S;
int func_int(){
int n = 100 ;
return n;
}
S func_s(){
S a;
a.a = 100 ;
a.b = 200 ;
return a;
}
S operator + (const S &A, const S &B){
S C;
C.a = A.a + B.a;
C.b = A.b + B.b;
return C;
}
int main(){
int m = 100 , n = 36 ;
const int &r1 = m + n;
const int &r2 = m + 28 ;
const int &r3 = 12 * 3 ;
const int &r4 = 50 ;
const int &r5 = func_int();
S s1 = { 23 , 45 };
S s2 = { 90 , 75 };
const S &r6 = func_s();
const S &r7 = s1 + s2;
return 0 ;
}
|
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
最后于 2023-11-8 00:29
被calleng编辑
,原因: 修改大纲,填充内容