【难点】指针引用
[email protected]:~/c++$ cat main.cpp #include <stdlib.h> #include "iostream" using namespace std; int a = 20; struct Teacher { int age; char name[64]; }; int fun1(struct Teacher ** p) { int ret = 0; if(p == NULL) { ret = -1; return ret; } Teacher *tmp = (Teacher *)malloc(sizeof(struct Teacher)); tmp -> age = 20; *p = tmp; // p的值是一个地址,*p就是修改这个地址里面的值 return a; } int fun2(struct Teacher *&p) { //这里的p就是主函数的p int ret = 0; if(p == NULL) { ret = -1; return ret; } p = (struct Teacher *)malloc(sizeof(struct Teacher)); p->age = 30; } void fun3(struct Teacher *p) { if(p == NULL) { return ; } free(p); } int main() { struct Teacher *p = NULL; fun1(&p);cout << p->age << endl;fun3(p); fun2(p);cout << p->age << endl;fun3(p);//此时编译器已经帮我们取地址了 return 0; } [email protected]:~/c++$ g++ main.cpp && ./a.out 20 30 [email protected]:~/c++$
【常引用基础】
让变量引用只读属性,不能再修改变量的值了
[email protected]:~/c++$ cat main.cpp #include "iostream" using namespace std; int main() { int a = 10; const int &b = a; b = 20; return 0; } [email protected]:~/c++$ g++ main.cpp && ./a.out main.cpp: In function ‘int main()’: main.cpp:8:4: error: assignment of read-only reference ‘b’ b = 20; ^
【常引用的初始化1】
[email protected]:~/c++$ cat main.cpp #include "iostream" using namespace std; int main() { int a = 10; const int &b = a; cout << b << endl; return 0; } [email protected]:~/c++$ g++ main.cpp && ./a.out 10
常引用初始化2,用字面量初始化常量·常量引用
这样写编译不通过
[email protected]:~/c++$ cat main.cpp #include "iostream" using namespace std; int main() { int a = 10; int &b = 11; //引用的是一个字面量 cout << b << endl; return 0; } [email protected]:~/c++$ g++ main.cpp && ./a.out main.cpp: In function ‘int main()’: main.cpp:6:11: error: invalid initialization of non-const reference of type ‘int&’ from an rvalue of type ‘int’ int &b = 11; ^
修改一下,就可以啦
[email protected]:~/c++$ cat main.cpp #include "iostream" using namespace std; int main() { int a = 10; const int &b = 11; // C++编译器会分配内存空间 cout << b << endl; return 0; } [email protected]:~/c++$ g++ main.cpp && ./a.out 11
常引用初始化2常量引用做函数参数,
让实参拥有只读属性
[email protected]:~/c++$ cat main.cpp #include "iostream" using namespace std; //相当于 const int * const a int fun(const int &a) { cout<< a <<endl; } int main() { int a = 10; fun(a); return 0; } [email protected]:~/c++$ g++ main.cpp && ./a.out 10
【内联函数】
说明1:
必须inline int myfunc(int a,int b)和函数体的实现,写在一块
说明2
C++编译器可以将一个函数进行内联编译
被C++编译器内联编译的函数叫做内联函数
内联函数在最终生成的代码中是没有定义的
C++编译器直接将函数体插入在函数调用的地方
内联函数没有普通函数调用时的额外开销(压栈,跳转,返回)
说明3:C++编译器不一定准许函数的内联请求!
说明4
内联函数是一种特殊的函数,具有普通函数的特征(参数检查,返回类型等)
内联函数是对编译器的一种请求,因此编译器可能拒绝这种请求
内联函数由编译器处理,直接将编译后的函数体插入调用的地方
宏代码片段由预处理器处理,进行简单的文本替换,没有任何编译过程
说明5:
现代C++编译器能够进行编译优化,因此一些函数即使没有inline声明,也可能被编译器内联编译
另外,一些现代C++编译器提供了扩展语法,能够对函数进行强制内联
如:g++中的__attribute__((always_inline))属性
说明6:
C++中内联编译的限制:
不能存在任何形式的循环语句
不能存在过多的条件判断语句
函数体不能过于庞大
不能对函数进行取址操作
函数内联声明必须在调用语句之前
编译器对于内联函数的限制并不是绝对的,内联函数相对于普通函数的优势只是省去了函数调用时压栈,跳转和返回的开销。
因此,当函数体的执行开销远大于压栈,跳转和返回所用的开销时,那么内联将无意义。
结论:
1)内联函数在编译时直接将函数体插入函数调用的地方
2)inline只是一种请求,编译器不一定允许这种请求
3)内联函数省去了普通函数调用时压栈,跳转和返回的开销
[email protected]:~/c++$ cat main.cpp #include "iostream" using namespace std; inline void fun() { cout<< "Hello World!" <<endl; } int main() { fun(); return 0; } [email protected]:~/c++$ g++ main.cpp && ./a.out Hello World!
带参数的宏
[email protected]:~/c++$ cat main.cpp #include "iostream" using namespace std; //带参数的宏.谨慎带有++ --的参数 #define FUN(a,b) ((a) < (b)? (a):(b)) inline int fun(int a,int b) { return a < b ? a:b; } int main() { int var1 = 1; int var2 = 3; int a = FUN(++var1,var2++); cout << a <<endl; a = fun(++var1,var2++); cout << a <<endl; return 0; } [email protected]:~/c++$ g++ main.cpp && ./a.out 3 4
函数默认值:
默认参数要么全部都有,要么只在右边
[email protected]:~/c++$ cat main.cpp #include "iostream" using namespace std; int fun(int a,int b =4) { cout << a << " " << b << endl; } int main() { fun(1); return 0; } [email protected]:~/c++$ g++ main.cpp && ./a.out 1 4
如果默认参数在前面,后面也有参数但是没有默认参数,编译报错
默认参数应该在函数的右边
[email protected]:~/c++$ cat main.cpp #include "iostream" using namespace std; int fun(int a =1,int b) { cout << a << " " << b << endl; } int main() { fun(1,2); return 0; } [email protected]:~/c++$ g++ main.cpp && ./a.out main.cpp: In function ‘int fun(int, int)’: main.cpp:4:5: error: default argument missing for parameter 2 of ‘int fun(int, int)’ int fun(int a =1,int b) ^
函数占位参数
调用时,必须写够参数
[email protected]:~/c++$ cat main.cpp #include "iostream" using namespace std; int fun(int a ,int b,int) { cout <<a << " "; cout <<b << endl; } int main() { fun(1,2,4); return 0; } [email protected]:~/c++$ g++ main.cpp && ./a.out 1 2
默认参数 与 占位符在一起
[email protected]:~/c++$ cat main.cpp #include "iostream" using namespace std; //默认参数 与 占位符在一起 void fun(int a ,int b,int = 0) { cout <<a << " "; cout <<b << endl; } int main() { fun(3,2); fun(1,2,4); return 0; } [email protected]:~/c++$ g++ -Wall -g main.cpp && ./a.out 3 2 1 2
函数重载:【面试重点】
函数名必须一致
函数返回值类型必须一致
函数的实参类型不一致
[email protected]:~/c++$ cat main.cpp #include "iostream" using namespace std; int fun(int a) { cout <<a << "\n"; return 1; } int fun(int *p) { cout << *p << "\n"; return 2; } int fun(int a ,int b) { cout <<a << " "; cout <<b << endl; return 3; } int main() { fun(1); fun(3,2); int a = 40; fun(&a); return 0; } [email protected]:~/c++$ g++ -Wall -g main.cpp && ./a.out 1 3 2 40
当函数重载遇到默认参数,C++编译器不允许通过,编译失败
[email protected]:~/c++$ cat main.cpp #include "iostream" using namespace std; int fun(int a ,int b) { cout <<a << " "; cout <<b << endl; return 1; } int fun(int a ,int b,int c = 0) { cout <<a << " "; cout <<b << " "; cout <<c << endl; return 2; } int main() { fun(3,2); return 0; } [email protected]:~/c++$ g++ -Wall -g main.cpp && ./a.out main.cpp: In function ‘int main()’: main.cpp:21:9: error: call of overloaded ‘fun(int, int)’ is ambiguous fun(3,2); ^
当存在二义性的重载函数,你不去调用,编译器就不会报错:
[email protected]:~/c++$ cat main.cpp #include "iostream" using namespace std; int fun(int a ) { cout <<a << endl; return 1; } int fun(int a ,int b) { cout <<a << " "; cout <<b << endl; return 1; } int fun(int a ,int b,int c = 0) { cout <<a << " "; cout <<b << " "; cout <<c << endl; return 2; } int main() { fun(3); return 0; } [email protected]:~/c++$ g++ -Wall -g main.cpp && ./a.out 3
函数指针的申明:三种方式:
[email protected]:~/c++$ cat main.cpp #include "iostream" using namespace std; //申明一个函数的数据类型 typedef void (fun1) (int a,int b) ;//自定义一个数据类型 //申明一个函数的数据类型 typedef void (*fun2) (int a,int b) ;//申明了一个指针的数据类型 //定义一个函数指针的变量 void (*fun3)(int a,int b); int main() { fun1 *p1 = NULL; //定义一个函数指针,指向函数的入口地址 fun2 p2 = NULL; //定义一个函数指针,指向函数的入口地址 return 0; } [email protected]:~/c++$ g++ -g main.cpp && ./a.out
当函数重载与函数指针在一起
[email protected]:~/c++$ cat main.cpp #include "iostream" using namespace std; void fun(int a,int b) { cout << a << endl; cout << b << endl; } void fun(int a) { cout << a << endl; } int main() { typedef void (*p_fun) (int a,int b) ; //申明了一个指针的数据类型 p_fun p = NULL; //定义一个函数指针,指向函数的入口地址 p = fun; p(1,3); //p(3); //会报错 return 0; } [email protected]:~/c++$ g++ -g main.cpp && ./a.out 1 3
========= C++ 对C 的扩展 结束 =============
【类的初步】
类的初步:
类是抽象的,并没有内存空间
对象是具体的
计算圆的面积:
[email protected]:~/c++$ cat main.cpp #include "iostream" using namespace std; class Mycricle { public : double m_r; double m_s; public : double set_r(double r) { m_r = r; } double get_r() { return m_r; } double get_s() { m_s = 3.14 * m_r *m_r; return m_s; } }; int main() { Mycricle c1 ,c2; c1.set_r(10); cout << c1.get_s() << endl; c2.set_r(1); cout << c2.get_s() << endl; return 0; } [email protected]:~/c++$ g++ -g main.cpp && ./a.out 314 3.14
【封装的含义1】
类的威力,用类当函数的参数:
比原来的结构体功能强大很多!
1,类指针
[email protected]:~/c++$ cat main.cpp #include "iostream" using namespace std; class Mycricle { public : double m_r; double m_s; public : void set_r(double r) { m_r = r; } double get_r() { return m_r; } double get_s() { m_s = 3.14 * m_r *m_r; return m_s; } }; void fun(Mycricle *p) { cout << "r="<<p->get_r() ; cout << " s="<<p->get_s() << endl; } int main() { Mycricle c1 ,c2; c1.set_r(10); fun(&c1); c2.set_r(1); fun(&c2); return 0; } [email protected]:~/c++$ g++ -Wall -g main.cpp && ./a.out r=10 s=314 r=1 s=3.14 [email protected]:~/c++$
【封装的含义1】
类的威力,用类当函数的参数:
比原来的结构体功能强大很多!
1,类引用
[email protected]:~/c++$ cat main.cpp #include "iostream" using namespace std; class Mycricle { public : double m_r; double m_s; public : void set_r(double r) { m_r = r; } double get_r() { return m_r; } double get_s() { m_s = 3.14 * m_r *m_r; return m_s; } }; void fun(Mycricle &p) { cout << "r="<<p.get_r() ; cout << " s="<<p.get_s() << endl; } int main() { Mycricle c1 ,c2; c1.set_r(10); fun(c1); c2.set_r(1); fun(c2); return 0; } [email protected]:~/c++$ g++ -Wall -g main.cpp && ./a.out r=10 s=314 r=1 s=3.14
类的控制:
public 修饰的成员变量和函数,可以在类的内部和类的外部访问
private 修饰的成员变量和函数,只能可以在类的内部访问,不能在类的外部访问
private 修饰的成员变量和函数,只能可以在类的内部访问,不能在类的外部访问
[email protected]:~/c++$ cat main.cpp #include "iostream" using namespace std; class Mycricle { private : double m_r; double m_s; public : void set_r(double r) { m_r = r; } double get_r() { return m_r; } double get_s() { m_s = 3.14 * m_r *m_r; return m_s; } }; void fun(Mycricle &p) { cout << "r="<<p.get_r() ; cout << " s="<<p.get_s() << endl; } int main() { Mycricle c1 ,c2; c1.set_r(10); fun(c1); c2.set_r(1); fun(c2); c1.m_r = 10; return 0; } [email protected]:~/c++$ g++ -Wall -g main.cpp && ./a.out main.cpp: In function ‘int main()’: main.cpp:7:9: error: ‘double Mycricle::m_r’ is private double m_r; ^ 提示这是一个private类型
默认属性就是私有属性
[email protected]:~/c++$ cat main.cpp #include "iostream" using namespace std; class Mycricle { int age;//默认清空下,这是一个私有属性 }; int main() { Mycricle c; c.age = 10; return 0; } [email protected]:~/c++$ g++ -Wall -g main.cpp && ./a.out main.cpp: In function ‘int main()’: main.cpp:6:6: error: ‘int Mycricle::age’ is private int age;//默认清空下,这是一个私有属性 ^
在c++中结构体的默认属性的public
[email protected]:~/c++$ cat main.cpp #include "iostream" using namespace std; struct test { int age;//默认清空下,是public属性 }; int main() { test t1; t1.age = 10; return 0; } [email protected]:~/c++$ cat main.cpp #include "iostream" using namespace std; struct test { int age;//默认清空下,是public属性 }; int main() { test t1; t1.age = 10; cout << t1.age << endl; return 0; } [email protected]:~/c++$ g++ -Wall -g main.cpp && ./a.out 10
类的申明与实现,分开:
1主函数
[email protected]:~/c++$ cat main.cpp #include "teacher.h" #include "iostream" using namespace std; int main() { teacher t1; t1.set_age(36); cout<< (t1.get_age()) << "\n"; return 0; }
2类的声明
[email protected]:~/c++$ cat teacher.h #pragma once #ifndef __TEACHER_H_ #define __TEACHER_H_ class teacher { private: int age; char name[32]; public: void set_age(int a); int get_age(); }; #endif
3,类的实现
[email protected]:~/c++$ cat teacher.cpp #include "teacher.h" void teacher::set_age(int a) { age = a; } int teacher::get_age() { return age; }
编译运行
[email protected]:~/c++$ g++ -g main.cpp teacher.cpp && ./a.out 36
转变到面向对象转变过程
[email protected]:~/c++$ cat mycube.cpp #include <iostream> using namespace std; class Cube { public: void set_abc(int a=0,int b=0,int c=0) { m_a = a; m_b = b; m_c = c; } int get_v() { m_v = m_a * m_b * m_c; return m_v; } int get_s() { m_s = 2*((m_a * m_b)+(m_a * m_c)+(m_b * m_c)); return m_s; } private: int m_a; int m_b; int m_c; int m_v; int m_s; }; int main() { Cube v1; v1.set_abc(1,1,1); cout << "体积= "<<v1.get_v() << endl; cout << "面积= "<<v1.get_s() << endl; return 0; } [email protected]:~/c++$ g++ -Wall -g mycube.cpp && ./a.out 体积= 1 面积= 6
加料啦!
比较两个立方体的是否一样
1,用外部函数来比较
[email protected]:~/c++$ cat mycube.cpp #include <iostream> using namespace std; class Cube { public: void set_abc(int a=0,int b=0,int c=0) { m_a = a; m_b = b; m_c = c; } int get_v() { m_v = m_a * m_b * m_c; return m_v; } int get_s() { m_s = 2*((m_a * m_b)+(m_a * m_c)+(m_b * m_c)); return m_s; } int get_a(){return m_a;} int get_b(){return m_b;} int get_c(){return m_c;} private: int m_a; int m_b; int m_c; int m_v; int m_s; }; int main() { Cube v1; v1.set_abc(1,1,1); Cube v2; v2.set_abc(1,1,3); if(v1.get_a() == v2.get_a() && v1.get_b() == v2.get_b() && v1.get_c() == v2.get_c()) { cout << "equal \n"; } else { cout << "not equal \n"; } return 0; } [email protected]:~/c++$ g++ -Wall -g mycube.cpp && ./a.out not equal
用面向对象的方式 实现立方体的比较
[email protected]:~/c++$ cat mycube.cpp #include <iostream> using namespace std; class Cube { public: void set_abc(int a=0,int b=0,int c=0) { m_a = a; m_b = b; m_c = c; } int get_v() { m_v = m_a * m_b * m_c; return m_v; } int get_s() { m_s = 2*((m_a * m_b)+(m_a * m_c)+(m_b * m_c)); return m_s; } int get_a(){return m_a;} int get_b(){return m_b;} int get_c(){return m_c;} int judge(Cube &v) { //cout << "m_a=" << m_a <<" "; //cout << "m_b=" << m_b <<" "; //cout << "m_c=" << m_c <<"\n"; //cout << "get_a=" << v.get_a() <<" "; //cout << "get_b=" << v.get_b() <<" "; //cout << "get_c=" << v.get_c() <<"\n"; if( m_a == v.get_a()&& m_b == v.get_b()&& m_c == v.get_c()) { return 1; } else { return 0; } } private: int m_a; int m_b; int m_c; int m_v; int m_s; }; int main() { Cube v1; v1.set_abc(1,1,1); Cube v2; v2.set_abc(1,1,1); if(v1.judge(v2) == 1){cout << "equal \n";} else{ cout << "not equal \n"; } return 0; } [email protected]:~/c++$ g++ -Wall -g mycube.cpp && ./a.out equal
用面向对象的思路求【点】是否在【圆】内
涉及到两个类,一个是点,一个是圆
源代码:
[email protected]:~/c++$ cat mycube.cpp #include <iostream> using namespace std; //class MyPoint; 这是类的前置申明 class MyPoint { public: int get_x(){return x1;} int get_y(){return y1;} void setPoint(int _x1,int _y1) { x1 = _x1; y1 = _y1; } private: int x1; int y1; }; class advCircle { public: void setCircle(int _r,int _x0,int _y0) { r = _r; x0 = _x0; y0 = _y0; } int judge(MyPoint &p) { int l = (p.get_x() - x0) * (p.get_y() -y0); if(r * r > l) { return 1; } else { return 0; } } private: int r; int x0; int y0; }; int main() { advCircle c1; c1.setCircle(2,3,3); MyPoint p1; p1.setPoint(7,7); if(c1.judge(p1) ==1 ) { cout << "在圆内\n"; } else { cout << "在圆外\n"; } return 0; } [email protected]:~/c++$ g++ -Wall -g mycube.cpp && ./a.out 在圆外
把类的申明与实现分开写:
有这么5个文件:
[email protected]:~/c++$ ll total 20K -rw-rw-r-- 1 chunli chunli 347 Jun 28 16:46 advCircle.cpp -rw-rw-r-- 1 chunli chunli 253 Jun 28 16:49 advCircle.h -rw-rw-r-- 1 chunli chunli 263 Jun 28 16:50 main.cpp -rw-rw-r-- 1 chunli chunli 172 Jun 28 16:39 MyPoint.cpp -rw-rw-r-- 1 chunli chunli 215 Jun 28 16:42 MyPoint.h
文件1:
[email protected]:~/c++$ cat advCircle.h #pragma once #include "MyPoint.h" #ifndef __ADVCIRCLE_H_ #define __ADVCIRCLE_H_ class advCircle { public: void setCircle(int _r,int _x0,int _y0); int judge(MyPoint &p); private: int r; int x0; int y0; }; #endif
文件2:
[email protected]:~/c++$ cat advCircle.cpp #include "advCircle.h" void advCircle::setCircle(int _r,int _x0,int _y0) { r = _r; x0 = _x0; y0 = _y0; } int advCircle::judge(MyPoint &p) { int l = (p.get_x() - x0) * (p.get_y() -y0); if(r * r > l) { return 1; } else { return 0; } }
文件3:
[email protected]:~/c++$ cat MyPoint.h #pragma once #ifndef __MYPOINT_H_ #define __MYPOINT_H_ class MyPoint { private: int x1; int y1; public: int get_x(); int get_y(); void setPoint(int _x1,int _y1); }; #endif
文件4:
[email protected]:~/c++$ cat MyPoint.cpp #include "MyPoint.h" int MyPoint::get_x(){return x1;} int MyPoint::get_y(){return y1;} void MyPoint::setPoint(int _x1,int _y1) { x1 = _x1; y1 = _y1; }
文件5:
[email protected]:~/c++$ cat main.cpp #include "MyPoint.h" #include "advCircle.h" #include <iostream> using namespace std; int main() { advCircle c1; c1.setCircle(2,3,3); MyPoint p1; p1.setPoint(7,7); if(c1.judge(p1) ==1 ) { cout << "在圆内\n";} else { cout << "在圆外\n";} return 0; }
编译运行:
[email protected]:~/c++$ g++ -g main.cpp MyPoint.cpp advCircle.cpp && ./a.out 在圆外
作业: