学习C++的道路 博主会持续更新的
2018.9.3 今天开始正式上课了 也是好好开始学习C++的日子了
今天买了两本书 C++项目开发 与 C接口----等我的书回来一定要好好的学习一波
博主用的编译软件是VS2017 ----- 地址 : https://visualstudio.microsoft.com/zh-hans/vs/whatsnew/
今天:学习了利用继承改写组合关系 我把今天写的笔记总结了下来 如下(有写的不对的地方,大家不要见怪 提出来我们共同解决):
1 /* 2 8:继承使用的两种情况 3 (1)、类之间有自然的继承关系,一个类另一个类的特例。 4 fx:一个学生是一个人 5 (2)、实现代码复用,一个类需要使用另一个类中的成员时 6 9:继承的好处 7 (1)、代码复用 code reuse 8 (2)、使代码容易修改 9 10:两个类之间的交互关系 10 (1)、组合类 ------》 一个类中有另一个类的对象 has-a的关系 11 ====== 组合改继承 那么 我们可以一步一步去拆分进而去得到 12 (2)、继承 ------》 一个雷是另一个类的特例 is-a的关系 13 14 学到了学到了 输出运算符重载 15 ostream & operator << (ostream & os, Point & apoint){ 16 os << "Point:X:Y: "<<apoint.x<<","<<apoint.y<<"\n"; 17 return os; 18 //其中 Point是具体的某一个类 这个类名是可以进行更改的 19 } 20 21 */ 22 #include <iostream> 23 using namespace std; 24 class Point { 25 26 }; 27 28 class Circle { 29 private: 30 Point center; 31 float radius; 32 }; 33 34 class Cylinder { 35 private: 36 Circle c; 37 float height; 38 }; 39 40 //上边是用组合来写的 41 //接下来给出用继承来写 42 class Point1{ 43 private: 44 float x, y; 45 }; 46 47 class Circle1:Point1 { 48 private: 49 float radious; 50 }; 51 52 class Cylinder : Circle1 { 53 private: 54 float height; //自己扩展 + 父类的成员 + 爷爷的成员 55 }; 56 57 //接下来书写组合改继承的具体代码 注意:与上边要分开 否则一起运行时会报错的 58 59 #include <iostream> 60 #include <cmath> 61 using namespace std; 62 63 class Point { 64 friend ostream & operator << (ostream & , Point & ); 65 protected: 66 double x, y; 67 public: 68 Point():x(0),y(0){} 69 Point(double _x, double _y) { 70 x = _x; 71 y = _y; 72 } 73 }; 74 75 ostream & operator << (ostream & os, Point & apoint) { 76 os << "Point:X:Y " << apoint.x << "." << apoint.y << "\n"; 77 return os; 78 } 79 80 //圆继承点 81 class Circle : public Point{ 82 friend ostream & operator << (ostream &, Circle &); 83 protected: 84 double radius; 85 public: 86 Circle():Point(),radius(0){} 87 Circle(double r,double xval,double yval):Point(xval,yval),radius(r){} 88 89 double area() { 90 return (3.14159 * radius * radius); 91 } 92 }; 93 94 ostream & operator << (ostream & os, Circle & aCircle) { 95 os << "Cicle:radius:" << aCircle.radius; 96 os << aCircle.x << "\n"; 97 os << aCircle.y << "\n"; 98 return os; 99 } 100 101 class Cylinder :public Circle { 102 friend ostream & operator << (ostream &, Cylinder &); 103 protected: 104 double height; 105 public: 106 Cylinder() :Circle() { height = 0.0; } 107 Cylinder(double hv, double rv, double xv, double yv) :Circle(rv, xv, yv) { 108 height = hv; 109 } 110 111 double area() { 112 return (2 * Circle::area() + 2 * 3.14159 * radius * height); 113 } 114 }; 115 116 ostream & operator << (ostream & os, Cylinder & acylinder) { 117 os << "cylinder dimensions"; 118 os << "x:" << acylinder.x; 119 os << " y:" << acylinder.y; 120 os << " radius: " << acylinder.radius; 121 os << " height: " << acylinder.height << endl; 122 return os; 123 } 124 125 int main(int argc, const char * argv[]) { 126 Point p(2, 3); 127 Circle c(7, 6, 5); 128 Cylinder cyl(10, 11, 12, 13); //半径不同 调用的函数变量的值不同 129 130 cout << p; 131 cout << c; 132 cout << "area circle:" << c.area() << endl; 133 134 cout << cyl; 135 cout << "area cylinder:" << cyl.area() << endl; 136 137 cout << "area cylinder base is " << cyl.Circle::area() << endl; 138 139 return 0; 140 }
很开心今天书回来了 好好学习
//今天学习到很过干货
1、子类的析构函数会自动会调用父类的析构函数
2、析构函数是存储保存在栈中的 所以在输出析构函数的时候是有一定的顺序的
3、虚函数----》这是个重点
(1)、在使用虚函数之后可以不去使用向下转型
(2)、期望父类指针。不管指向父类还是子类,在调用override函数是,反映真实情况
(3)、指针或者引用所指向的对象的类型来确定
4、多态-----个人理解(多种形态)
fx:
//Base *p = &d1; //其实与多态类似 主类的指针在不断的变化
//p = &d2; //虚函数的时候只需要改指向就ok
//p = &b; //指哪一个调用哪一个
今天的代码:
1 //虚函数与多态 2 /* 3 虚函数的使用(根据父类的引用的指向来选择进行哪一个实现) 4 虚函数的作用: 5 (1)、无需向下转型,就可以正确的用父类的指针或引用 6 (2)、期望父类指针。不管指向父类还是子类,在调用override函数是,反映真实情况 7 (3)、指针或者引用所指向的对象的类型来确定 8 */ 9 #include <iostream> 10 using namespace std; 11 12 class Base { 13 public: 14 virtual void func() { 15 cout << "Base function" << endl; 16 } 17 }; 18 19 class Derived1 :public Base { 20 public: 21 void func() { 22 cout << "Derived1 function" << endl; 23 } 24 }; 25 26 class Derived2 :public Base { 27 public: 28 void func() { 29 cout << "Derived2 function" << endl; 30 } 31 }; 32 33 void foo(Base & b) { 34 b.func(); 35 } 36 37 int main() { 38 //虚函数(一) 39 /* 40 Base b; 41 Derived1 d; 42 Base *p = &d; //父类指针指向子类对象 43 Base & br = d; //父类引用指向子类对象 44 b.func(); //父类版本 45 d.func(); //子类版本 46 p->func(); //父类 47 br.func(); 48 foo(b); 49 */ 50 51 52 //虚函数(二) 53 Base b; 54 Derived1 d1; 55 Derived2 d2; 56 57 //Base *p = &d1; //其实与多态类似 主类的指针在不断的变化 58 //p = &d2; //虚函数的时候只需要改指向就ok 59 //p = &b; //指哪一个调用哪一个 60 //p->func(); 61 62 63 Base *p[3] = { &b,&d1,&d2 }; //父类指针数组 --------> 厉害 厉害 学到了 学到了 64 for (int i = 0; i < 3; ++i) 65 { 66 p[i]->func(); 67 } 68 return 0; 69 } 70 71 //加强虚函数的使用 72 #include <iostream> 73 using namespace std; 74 75 class Thing { 76 public: 77 virtual void what_Am_I() { 78 cout << "I am a Thing.\n"; 79 } 80 ~Thing() { 81 cout << "Thing destructor" << endl; 82 } 83 }; 84 85 class Animal : public Thing { 86 public: 87 virtual void what_Am_I() { 88 cout << "I am a Animal.\n"; 89 } 90 91 //子类析构函数会自动调用父类的析构函数 92 //注意析构函数的存储是保存在栈中的 所以这边输出的时候是有一定的顺序的 93 ~Animal() { 94 cout << "Animal destructor" << endl; 95 } 96 }; 97 98 int main() { 99 Thing t; 100 Animal x; 101 Thing* array[2]; //声明一个父类指针数组 102 array[0] = &t; 103 array[1] = &x; 104 for (int i = 0; i < 2; i++) { 105 array[i]->what_Am_I(); 106 } 107 return 0; 108 }
2018.9.5(上午10点 看了关于本地时间的一些函数)
http://www.runoob.com/cplusplus/cpp-date-time.html
一些代码
1 #include <iostream> 2 #include <bits/stdc++.h> 3 #include <ctime> 4 5 using namespace std; 6 7 /* 8 当地时间的结构体 用于ctime头文件中 9 struct tm { 10 int tm_sec; // 秒,正常范围从 0 到 59,但允许至 61 11 int tm_min; // 分,范围从 0 到 59 12 int tm_hour; // 小时,范围从 0 到 23 13 int tm_mday; // 一月中的第几天,范围从 1 到 31 14 int tm_mon; // 月,范围从 0 到 11 15 int tm_year; // 自 1900 年起的年数 16 int tm_wday; // 一周中的第几天,范围从 0 到 6,从星期日算起 17 int tm_yday; // 一年中的第几天,范围从 0 到 365,从 1 月 1 日算起 18 int tm_isdst; // 夏令时 19 } 20 */ 21 22 int main(int argc, char const *argv[]) 23 { 24 //基于当前系统的当前日期 25 time_t now = time(0); 26 27 //把 now转换成字符串形式 28 char* dt = ctime(&now); 29 30 cout<<"本地日期和时间: "<<dt<<endl; 31 32 //把now转换成为tm结构 33 tm * gmtm = gmtime(&now); 34 dt = asctime(gmtm); 35 cout<<"UTC日期和时间: "<<dt<<endl; 36 37 cout<<"1970 到目前经过的秒数: "<<now<<endl; 38 39 tm * ltm = localtime(&now); 40 41 //输出tm结构的各个组成部分 42 cout<<"年: "<<1900 + ltm->tm_year<<endl; 43 cout<<"月 "<<1 + ltm->tm_mon<<endl; 44 cout<<"日 "<<ltm->tm_mday<<endl; 45 cout<<"时间: "<<ltm->tm_hour<<endl; 46 cout<<ltm->tm_min<<":"; 47 cout<<ltm->tm_sec<<endl; 48 return 0; 49 }
2018.9.5(下午)
今天在学习虚函数的基础上,学习了虚析构函数。
在今天的学习中了解到,如果一个类是父类 那么它的析构函数就必须是虚函数
如果不是虚析构函数的话就会造成内存泄漏,会引起报错。(在C++学习中一定需要注意)
1 #include <iostream> 2 using namespace std; 3 4 class Base { 5 public: 6 Base(){} 7 virtual ~Base() { 8 cout << "Base destructor!" << endl; 9 } 10 }; 11 12 class Derived : public Base { 13 public: 14 Derived(){} 15 ~Derived() { 16 cout << "Derived destructor!" << endl; 17 } 18 }; 19 20 int main() { 21 Base p1; //存在于栈区 22 Base* p2 = new Base(); //存在于堆区 23 Base *p = new Derived(); //声明一个子类对象在堆空间 24 25 //当把父类的虚构函数变为虚函数是 释放得劲就是子类的成员 26 delete p; //调用父类的析构函数,子类只释放了继承自父类的成员 内存泄漏 27 return 0; 28 }
2018.9.10(前几天有事情,没有更新)
1、纯虚函数:虚函数只有声明,函数体=0;就是一个纯虚函数
2、拥有纯虚函数的类叫做抽象类,抽象类只能作为基类,不能实例化对象
3、抽象类提供不同种类的之类对象的一个接口
4、纯虚函数被定义在派生类中。如果派生类不重写基类的纯虚函数,则派生类也是一个抽象类
1 /* 2 抽象基类与纯虚函数 3 */ 4 5 #include <iostream> 6 #include <math.h> 7 using namespace std; 8 9 class Point 10 { 11 private: 12 double x; 13 double y; 14 public: 15 Point(double i, double j) :x(i), y(j) {} 16 17 void print() const 18 { 19 cout << "(" << x << "," << y << ")" << endl; 20 } 21 }; 22 23 class Figure 24 { 25 private: 26 Point center; 27 public: 28 Figure(double i = 0, double j = 0) :center(i, j) {} 29 30 Point& location() 31 { 32 return center; 33 } 34 35 void move(Point p) 36 { 37 center = p; //改变图形的中心点 38 draw(); //调用draw对图形重新绘制 39 } 40 //纯虚函数 虚函数只有声明,没有实现,函数体 = 0 41 virtual void draw() = 0; 42 virtual void rotate(double) = 0; // 旋转图形 也没有实现 43 }; 44 class Circle :public Figure 45 { 46 private: 47 double radius; 48 public: 49 Circle(double i = 0, double j = 0, double r = 0):Figure(i,j),radius(r){} 50 void draw() //对父类的Figure中的纯虚函数进行实现 51 { 52 cout << "A circle with center" << endl; 53 Figure::location().print(); 54 } 55 };
2018,.9.11(今天学习了多继承)
1、第一种
1 #include <iostream> 2 using namespace std; 3 4 class A 5 { 6 private: 7 int i; 8 public: 9 A(int i):i(i){} 10 void print() 11 { 12 cout << i << endl; 13 } 14 }; 15 16 class B 17 { 18 private: 19 int j; 20 public: 21 B(int j) :j(j) {} 22 void print() 23 { 24 cout << j << endl; 25 } 26 }; 27 28 class C :public A, B 29 { 30 private: 31 int k; 32 public: 33 C(int i,int j,int k):A(i),B(j),k(k){} 34 void get_Message() 35 { 36 A::print(); 37 B::print(); 38 } 39 }; 40 41 int main() 42 { 43 C x(5, 8, 10); 44 x.get_Message(); 45 46 47 //x.print(); 会报错 因为它不知道去调用哪一个父类的print函数 48 49 //针对上一个问题的方法 在子类调用print函数时加上某个父类的作用域函数 50 x.A::print(); 51 return 0; 52 }
2、第二种(菱形继承)
下边代码分两种情况 (1)、一个错误情况 (2)、正确情况
1 //2、菱形继承(有共同祖先) 二义性 代码解释 2 #include <iostream> 3 using namespace std; 4 5 class R //祖先类 6 { 7 private: 8 int r; 9 public: 10 R(int anInt) { r = anInt; } 11 void printOn() const { cout << "r=" << r << endl; } 12 }; 13 14 //父类A 15 class A : public R 16 { 17 int a; //父类A会有一份r 18 public: 19 A(int int1, int int2) :R(int2) { a = int1; } 20 }; 21 22 //父类B 23 class B : public R 24 { 25 int b; //父类B会有一份r 26 public: 27 B(int int1, int int2) :R(int2) { b = int1; } 28 }; 29 30 //孙子辈的子类继承父类A和B 31 class C :public A, public B 32 { 33 int c; //子类会有两份r,一份来自A,一份来自B 34 public: 35 C(int int1, int int2, int int3) :A(int2, int3), B(int2, int3) { c = int1; } 36 37 }; 38 39 int main() 40 { 41 R rr(10); 42 A aa(20, 30); 43 B bb(40, 50); 44 C cc(5, 7, 9); 45 rr.printOn(); 46 aa.printOn(); 47 bb.printOn(); 48 cc.printOn(); //error vs直接报错 不明确 49 return 0; 50 } 51 52 /* 53 为了解决二义性 我们需要使用虚继承 54 虚继承 55 1、直接继承祖先的两个基类,在继承是加virtual 56 2、通过多重继承而来的那个子类,在构造函数时,要调用祖先类的 57 构造函数。 58 */ 59 60 include <iostream> 61 using namespace std; 62 63 class R //祖先类 64 { 65 private: 66 int r; 67 public: 68 R(int anInt) { r = anInt; } 69 void printOn() const { cout << "r=" << r << endl; } 70 }; 71 72 //父类A 虚继承 73 class A :virtual public R 74 { 75 int a; //父类A会有一份r 76 public: 77 A(int int1, int int2) :R(int2) { a = int1; } 78 }; 79 80 //父类B 虚继承 81 class B :virtual public R 82 { 83 int b; //父类B会有一份r 84 public: 85 B(int int1, int int2) :R(int2) { b = int1; } 86 }; 87 88 //孙子辈的子类继承父类A和B 89 class C :public A, public B 90 { 91 int c; //子类直接继承祖先类R的成员,再继承两个父类各自扩张的成员 92 public: 93 C(int int1, int int2, int int3 ,int int4) :R(int1),A(int2, int1), B(int2, int1) { c = int4; } 94 95 }; 96 97 int main() 98 { 99 R rr(10); 100 A aa(20, 30); 101 B bb(40, 50); 102 C cc(5, 7, 9,10); 103 rr.printOn(); 104 aa.printOn(); 105 bb.printOn(); 106 cc.printOn(); 107 /* 108 因为虚继承C中的r和printOn函数直接从R类中继承,所以孙子类中 109 只会有一份R的成员,不会重复继承 110 */ 111 return 0; 112 }