【难点】指针引用
chunli@Linux:~/c++$ cat main.cpp #include#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;}chunli@Linux:~/c++$ g++ main.cpp && ./a.out 2030chunli@Linux:~/c++$
【常引用基础】
让变量引用只读属性,不能再修改变量的值了
chunli@Linux:~/c++$ cat main.cpp #include "iostream" using namespace std;int main(){ int a = 10; const int &b = a; b = 20; return 0;}chunli@Linux:~/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】
chunli@Linux:~/c++$ cat main.cpp #include "iostream" using namespace std;int main(){ int a = 10; const int &b = a; cout << b << endl; return 0;}chunli@Linux:~/c++$ g++ main.cpp && ./a.out 10
常引用初始化2,用字面量初始化常量·常量引用
这样写编译不通过
chunli@Linux:~/c++$ cat main.cpp #include "iostream" using namespace std;int main(){ int a = 10; int &b = 11; //引用的是一个字面量 cout << b << endl; return 0;}chunli@Linux:~/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; ^
修改一下,就可以啦
chunli@Linux:~/c++$ cat main.cpp #include "iostream" using namespace std;int main(){ int a = 10; const int &b = 11; // C++编译器会分配内存空间 cout << b << endl; return 0;}chunli@Linux:~/c++$ g++ main.cpp && ./a.out 11
常引用初始化2常量引用做函数参数,
让实参拥有只读属性
chunli@Linux:~/c++$ cat main.cpp #include "iostream" using namespace std;//相当于 const int * const aint fun(const int &a){ cout<< a <
【内联函数】
说明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)内联函数省去了普通函数调用时压栈,跳转和返回的开销
chunli@Linux:~/c++$ cat main.cpp #include "iostream" using namespace std;inline void fun(){ cout<< "Hello World!" <
带参数的宏
chunli@Linux:~/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 <
函数默认值:
默认参数要么全部都有,要么只在右边
chunli@Linux:~/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;}chunli@Linux:~/c++$ g++ main.cpp && ./a.out 1 4
如果默认参数在前面,后面也有参数但是没有默认参数,编译报错
默认参数应该在函数的右边
chunli@Linux:~/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;}chunli@Linux:~/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) ^
函数占位参数
调用时,必须写够参数
chunli@Linux:~/c++$ cat main.cpp #include "iostream" using namespace std;int fun(int a ,int b,int){ cout < << " "; cout < << endl;}int main(){ fun(1,2,4); return 0;}chunli@Linux:~/c++$ g++ main.cpp && ./a.out 1 2
默认参数 与 占位符在一起
chunli@Linux:~/c++$ cat main.cpp #include "iostream" using namespace std;//默认参数 与 占位符在一起void fun(int a ,int b,int = 0){ cout < << " "; cout < << endl;}int main(){ fun(3,2); fun(1,2,4); return 0;}chunli@Linux:~/c++$ g++ -Wall -g main.cpp && ./a.out 3 21 2
函数重载:【面试重点】
函数名必须一致
函数返回值类型必须一致
函数的实参类型不一致
chunli@Linux:~/c++$ cat main.cpp #include "iostream" using namespace std;int fun(int a){ cout < << "\n"; return 1;}int fun(int *p){ cout << *p << "\n"; return 2;}int fun(int a ,int b){ cout < << " "; cout < << endl; return 3;}int main(){ fun(1); fun(3,2); int a = 40; fun(&a); return 0;}chunli@Linux:~/c++$ g++ -Wall -g main.cpp && ./a.out 13 240
当函数重载遇到默认参数,C++编译器不允许通过,编译失败
chunli@Linux:~/c++$ cat main.cpp #include "iostream" using namespace std;int fun(int a ,int b){ cout < << " "; cout < << endl; return 1;}int fun(int a ,int b,int c = 0){ cout < << " "; cout < << " "; cout <<< endl; return 2;}int main(){ fun(3,2); return 0;}chunli@Linux:~/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); ^
当存在二义性的重载函数,你不去调用,编译器就不会报错:
chunli@Linux:~/c++$ cat main.cpp #include "iostream" using namespace std;int fun(int a ){ cout < << endl; return 1;}int fun(int a ,int b){ cout < << " "; cout < << endl; return 1;}int fun(int a ,int b,int c = 0){ cout < << " "; cout < << " "; cout <<< endl; return 2;}int main(){ fun(3); return 0;}chunli@Linux:~/c++$ g++ -Wall -g main.cpp && ./a.out 3
函数指针的申明:三种方式:
chunli@Linux:~/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;}chunli@Linux:~/c++$ g++ -g main.cpp && ./a.out
当函数重载与函数指针在一起
chunli@Linux:~/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;}chunli@Linux:~/c++$ g++ -g main.cpp && ./a.out 13
========= C++ 对C 的扩展 结束 =============
【类的初步】
类的初步:
类是抽象的,并没有内存空间
对象是具体的
计算圆的面积:
chunli@Linux:~/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;}chunli@Linux:~/c++$ g++ -g main.cpp && ./a.out 3143.14
【封装的含义1】
类的威力,用类当函数的参数:
比原来的结构体功能强大很多!
1,类指针
chunli@Linux:~/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="<get_r() ; cout << " s="< get_s() << endl;}int main() { Mycricle c1 ,c2; c1.set_r(10); fun(&c1); c2.set_r(1); fun(&c2); return 0;}chunli@Linux:~/c++$ g++ -Wall -g main.cpp && ./a.out r=10 s=314r=1 s=3.14chunli@Linux:~/c++$
【封装的含义1】
类的威力,用类当函数的参数:
比原来的结构体功能强大很多!
1,类引用
chunli@Linux:~/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="<
类的控制:
public 修饰的成员变量和函数,可以在类的内部和类的外部访问
private 修饰的成员变量和函数,只能可以在类的内部访问,不能在类的外部访问
private 修饰的成员变量和函数,只能可以在类的内部访问,不能在类的外部访问
chunli@Linux:~/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="<
默认属性就是私有属性
chunli@Linux:~/c++$ cat main.cpp #include "iostream" using namespace std;class Mycricle{ int age;//默认清空下,这是一个私有属性};int main() { Mycricle c; c.age = 10; return 0;}chunli@Linux:~/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
chunli@Linux:~/c++$ cat main.cpp #include "iostream" using namespace std;struct test{ int age;//默认清空下,是public属性};int main() { test t1; t1.age = 10; return 0;}chunli@Linux:~/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;}chunli@Linux:~/c++$ g++ -Wall -g main.cpp && ./a.out 10
类的申明与实现,分开:
1主函数
chunli@Linux:~/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类的声明
chunli@Linux:~/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,类的实现
chunli@Linux:~/c++$ cat teacher.cpp #include "teacher.h"void teacher::set_age(int a){ age = a;}int teacher::get_age(){ return age;}
编译运行
chunli@Linux:~/c++$ g++ -g main.cpp teacher.cpp && ./a.out 36
转变到面向对象转变过程
chunli@Linux:~/c++$ cat mycube.cpp #includeusing 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 << "体积= "< << endl; cout << "面积= "< << endl; return 0;}chunli@Linux:~/c++$ g++ -Wall -g mycube.cpp && ./a.out 体积= 1面积= 6
加料啦!
比较两个立方体的是否一样
1,用外部函数来比较
chunli@Linux:~/c++$ cat mycube.cpp #includeusing 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;}chunli@Linux:~/c++$ g++ -Wall -g mycube.cpp && ./a.out not equal
用面向对象的方式 实现立方体的比较
chunli@Linux:~/c++$ cat mycube.cpp #includeusing 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;}chunli@Linux:~/c++$ g++ -Wall -g mycube.cpp && ./a.out equal
用面向对象的思路求【点】是否在【圆】内
涉及到两个类,一个是点,一个是圆
源代码:
chunli@Linux:~/c++$ cat mycube.cpp #includeusing 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;}chunli@Linux:~/c++$ g++ -Wall -g mycube.cpp && ./a.out 在圆外
把类的申明与实现分开写:
有这么5个文件:
chunli@Linux:~/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:
chunli@Linux:~/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:
chunli@Linux:~/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:
chunli@Linux:~/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:
chunli@Linux:~/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:
chunli@Linux:~/c++$ cat main.cpp #include "MyPoint.h"#include "advCircle.h"#includeusing 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;}
编译运行:
chunli@Linux:~/c++$ g++ -g main.cpp MyPoint.cpp advCircle.cpp && ./a.out 在圆外
作业:
第1题:
chunli@Linux:~/c++$ cat main.cpp #includeusing namespace std; class cricle{private: int r; int x; int y;public: int get_x(){return x;} int get_y(){return y;} int get_r(){return r;} void set_rxy() { cout << "请输入圆的半径,x,y坐标 "; cout << "如 1 4 2 代表半径为1,横坐标为4纵坐标为2\n"; cin >> r >> x >> y; } int judge(cricle c) { int l = (c.get_x() - x )* (c.get_x() - x ) + (c.get_y() - y) * (c.get_y() - y); int d = (r + c.get_r()) * (r + c.get_r()); if(d == l ) { return 0; } else if( d > l ) { return 1; } else { return -1; } }};int main(){ cricle c1; c1.set_rxy(); cricle c2; c2.set_rxy(); int ret = c1.judge(c2); if(ret == 0) { cout << "两圆相切\n"; } else if(ret == -1) { cout << "两圆相离\n"; } else { cout << "两圆相交\n"; } return 0;}chunli@Linux:~/c++$ 编译运行:chunli@Linux:~/c++$ g++ -g -Wall main.cpp && ./a.out 请输入圆的半径,x,y坐标 如 1 4 2 代表半径为1,横坐标为4纵坐标为21 2 2请输入圆的半径,x,y坐标 如 1 4 2 代表半径为1,横坐标为4纵坐标为21 3 2两圆相交chunli@Linux:~/c++$ g++ -g -Wall main.cpp && ./a.out 请输入圆的半径,x,y坐标 如 1 4 2 代表半径为1,横坐标为4纵坐标为21 2 2 请输入圆的半径,x,y坐标 如 1 4 2 代表半径为1,横坐标为4纵坐标为21 4 2两圆相切chunli@Linux:~/c++$ g++ -g -Wall main.cpp && ./a.out 请输入圆的半径,x,y坐标 如 1 4 2 代表半径为1,横坐标为4纵坐标为21 2 2 请输入圆的半径,x,y坐标 如 1 4 2 代表半径为1,横坐标为4纵坐标为21 5 2两圆相离
第2题:
chunli@Linux:~/c++$ cat main.cpp #includeusing namespace std; class Rectangle{private: int x1; int y1; int x2; int y2; int s;public: void set_xy(int _x1,int _y1,int _x2,int _y2) { x1 = _x1; y1 = _y1; x2 = _x2; y2 = _y2; } int get_s() { s = (x2 - x1) * (y2 -y1); return s; }};int main(){ Rectangle r1; r1.set_xy(0,0,4,4); cout << r1.get_s() << endl; return 0;}chunli@Linux:~/c++$ g++ -g -Wall main.cpp && ./a.out 16
第3题:
chunli@Linux:~/c++$ cat main.cpp #includeusing namespace std;class Tree{private: int n;public: void grow(int _age) { n = _age; } int age() { return n; }};int main(){ Tree t1; t1.grow(99); cout << t1.age() << endl; return 0;}chunli@Linux:~/c++$ g++ -g -Wall main.cpp && ./a.out 99