类和对象的学习
1.静态成员static
共享一份
类内声明,类外初始化,不属于某一个对象上,所有对象都共享同一份数据
因此静态成员有两种访问方式
1.通过对象来访问,同下即可
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 48 49 50 51 52 53
| #include<iostream> #include<algorithm> using namespace std; class Person { public: static int m_a; int m_c; static void func { cout<<"I love you"<<'\n'; } private: static int m_b; }; int Person:: m_a = 100; int Person:: m_b=100; void test01() { Person p1; cout << p1.m_a<<'\n'; Person p2; p2.m_a = 200; cout << p1.m_a <<'\n'; } void test02() { cout<<Person::m_a<<'\n'; } void test03() { Person p; p.func(); Person::func(); } int main() { test01(); 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
|
#include<iostream> #include<string> using namespace std; class Phone { public: Phone(string name) { cout << "手机被赋初值了" << '\n'; m_pname = name; } ~Phone() { cout << "析构函数的调用" << '\n'; } string m_pname; }; class Person { public: Person(string name, string pname) :m_name(name), m_phone(pname) { cout << "人被赋初值了" << '\n'; } ~Person() { cout << "人析构函数的调用" << '\n'; } string m_name; Phone m_phone; }; void test01() { Person p("张三", "华为"); cout << p.m_name << "拿着" << p.m_phone.m_pname<<'\n'; } int main() { test01(); }
|
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
| #include<iostream> #include<algorithm> using namespace std;
class Person { int m_a; static int m_b; void func() { } static void func { } }; int Person::m_b=100;
void test01() { Person p; cout << "size of p=" << sizeof(p) << '\n'; } void test02() { Person p; cout << "size of p=" << sizeof(p) << '\n'; } int main() { test02(); return 0; }
|
test 01()
代码展示结果
空对象占用内存空间是1
//C++编译器给每个空对象也分配一个字节空间
//是为了区分空对象占用的内存位置
//主要是为了区分
//size of p=1
//答案会是1
test 02()
代码展示结果
非静态成员变量属于类的对象上
size of p=4
3. this 指针
上一节课遗留的问题,成员函数要怎么调呢?
this指针指向被调用的成员函数所属的对象
this指针不需要定义
this指针隐含每一个非静态成员
作用
1.解决名称冲突
2.返回对象本身用* this
错误代码示范
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
| #include<iostream> #include<algorithm> using namespace std; class Person { public: Person(int age) { this->age = age; } void Personaddage(Person &p) { this->age+=p.age; } Person& Personaddage(Person &p) { this->age+=p.age; return *this; } int age; }; void test01() { Person p(18); cout << p.age; } void test02() { Person p1(10); Person p2(20); p2.Personaddage(p1); p2.Personaddage(p1).Personaddage(p1); cout<<p2.age<<'\n'; } int main() { test02(); return 0; }
|
4.空指针访问成员函数
如果是空指针需要预先说一下,避免程序崩溃
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
| #include<iostream> #include<string> using namespace std; class Person { public: void show() { cout << "I love you" << '\n'; } void showage() { if(this==NULL) { return ; } cout << "your age is" << m_age << '\n'; } int m_age; }; void test01() { Person* p = NULL; p->show(); p->showage();
} int main() { test01();
return 0; }
|
5.const修饰成员函数
成员函数加上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 39
| #include<iostream> using namespace std; class Person { public: void showPerson() const { this->m_b=1000; } int m_a; mutable int m_b; }; void test01() { Person p; p.showPerson(); } void test02() { const Person P; p.m_b=100; p.showPerson(); } int main() { test01(); }
|
6.友元
在程序里,有些私有属性让类外的特殊函数和特殊的类访问,就需要用到友元
友元的目的就是为了让一个函数或者一个类访问另一个类的私有成员
友元的关键字为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 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| #include<iostream> #include<string> using namespace std; class Buliding { friend void goodgay(Buliding* building); public: Buliding() { m_keting = "客厅"; m_woshi = "卧室"; } public: string m_keting; private: string m_woshi; }; void goodgay(Buliding* building) { cout << "访问中" << building->m_keting << '\n'; cout << "访问中" << building->m_woshi << '\n'; } void test01() { Buliding building; goodgay(&building); } int main() { test01(); return 0; }
|
2,类做友元
同样也是把那一句话加上 frirnd 放在函数里面
有一个新知识点,就是如果要类外初始化的话,我们需要在类内想进行声明,在类外加上::这个后才可以进行
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
| #include<iostream> #include<string> using namespace std; class Building { friend class goodgay; public: Building() { m_keting = "客厅"; m_woshi = "卧室"; } public: string m_keting; private: string m_woshi; }; class goodgay { public: goodgay();
void visit(); Building* buliding; };
goodgay::goodgay() { buliding = new Building; } void goodgay::visit() { cout << "正在访问" << buliding->m_keting << " " << buliding->m_woshi; } void test01() { goodgay gg; gg.visit(); } int main() { test01(); return 0; }
|
3.成员函数做友元
成员函数做友元的时候,那个不做友元的类需要事先声明,然后再进行那个友元的构建,其他和上面两种一样。
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
| #include<iostream> #include<string> using namespace std; class Building; class goodgay { public: goodgay(); void visit(); private: Building* buliding; }; class Building { friend void goodgay::visit(); public: Building() { m_keting = "客厅"; m_woshi = "卧室"; } public: string m_keting; private: string m_woshi; };
goodgay::goodgay() { buliding = new Building; } void goodgay::visit() { cout << "正在访问" << buliding->m_keting << " " ; cout << "正在访问" << buliding->m_woshi<<'\n'; }
void test01() { goodgay gg; gg.visit(); } int main() { test01(); return 0; }
|
7.运算符重载
1,加号运算符重载
引言:对于内置运算符,编译器知道如何运算,而其他数据类型呢?
我们有两种方法:成员函数重载在内部,需要用this,全局函数就可以不用This了,直接传入两个Person就可以了
总结1:对于内置数据类型的表达式的运算符是不可以重载的
总结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 48 49 50 51 52 53 54 55
| #include<iostream> using namespace std; class Person { public:
int m_a; int m_b; };
Person operator+ (Person p1,Person p2) { Person temp; temp.m_a = p1.m_a + p2.m_a; temp.m_b = p1.m_b + p2.m_b; return temp; } Person operator+ (Person p1, int num) { Person temp; temp.m_a = p1.m_a + num; temp.m_b = p1.m_b + num; return temp; }
void test01() { Person p1; p1.m_a = 10; p1.m_b = 10; Person p2; p2.m_a = 10; p2.m_b = 20; Person p3 = p1 + p2; cout << p3.m_a<<'\n'; cout << p3.m_b << '\n'; Person p4 = p1 + 10; cout << p4.m_a << '\n'; cout << p4.m_b << '\n'; } int main() { test01(); }
|
2.左移运算符重载
采取全局函数的重载方法,其次我们需要ostream,作为一个重载的工具。
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
| #include<iostream> using namespace std; class Person { friend ostream& operator<<(ostream& cout, Person& p); public: Person(int a,int b) { m_a = a; m_b = b; } private: int m_a; int m_b; };
ostream & operator<<(ostream &cout, Person &p) { cout << "m_a=" << p.m_a << " " << "m_b=" << p.m_b << '\n'; return cout; }
void test01() { Person p(10,10);
cout << p<<' '<<'\n';
} int main() { test01(); }
|
3.递增运算符重载
前置递增返回引用
后置递增返回值
因为局部变量的引用不能返回
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
| #include<iostream> using namespace std;
class Myinteger { public: friend ostream& operator<<(ostream& cout, Myinteger& myhint); Myinteger() { m_num = 0; } Myinteger & operator++() { m_num ++; return *this; } Myinteger operator++(int) { Myinteger temp = *this; m_num++; return temp; } private: int m_num; };
ostream& operator<<(ostream& cout, Myinteger &myhint) { cout << myhint.m_num; return cout; } void test01() { Myinteger myint; cout << ++(++myint); } void test02() { Myinteger myint; cout<< ++myint; }
int main() { test02(); }
|
4.赋值运算符重载
C++编译器会给一个类添加四个函数‘
第一个是构造函数,无参
第二个是析构函数,无参
第三个是拷贝构造函数,对属性进行值拷贝
第四个是赋值运算符 operator = 对属性进行值拷贝
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
| #include<iostream> using namespace std; class Person { public: Person(int age) { m_age = new int(age); } ~Person() { if (m_age != NULL) { delete m_age; m_age = NULL;
} } Person& operator=(Person& p) { if (m_age != NULL) { delete m_age; m_age = NULL; } m_age = new int(*p.m_age); return *this; } int* m_age; }; void test01() { Person p1(19); Person p2(20); p2 = p1; cout << *p1.m_age<<'\n'; cout << *p2.m_age; }
int main() { test01(); return 0; }
|
5.关系运算符重载
可以让两个自定义类型进行比较
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
|
#include<iostream> using namespace std; class Person { public: string m_name; int m_age; Person(string name, int age) { m_name = name; m_age = age; } bool operator==(Person &p) { if (this->m_name == p.m_name && this->m_age== p.m_age) { return 1; } return 0; } }; void test01() { Person p1("汤姆", 18); Person p2("汤姆", 18); if (p1 == p2) { cout << "p1和p2是相等的" << '\n'; } else { cout << "不相等" << '\n'; } } int main() { test01(); return 0;
}
|
6.函数调用运算符重载
函数调用运算符()也可以重载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 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| #include<iostream> #include<string> using namespace std; class myprint { public: void operator()(string test) { cout << test << '\n'; } }; class myadd { public: int operator()(int a, int b) { return a + b; } }; void test02() { myadd add; int x=add(199, 199); cout << x << '\n'; cout<<myadd()(100,100); } void test01() { myprint my; my("helloworld"); } int main() { test02(); return 0; }
|
8.继承
有些类指尖存在继承的关系,因此定义这些类的时候,下级别的成员除了拥有上一级的共性还有自己的特性。
这个时候可以用继承的方式减少重复代码
//基本实现方式在Public后面加上 public :base (继承的类)
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
| #include<iostream> using namespace std;
class bage { public: void header() { cout << "首页公开登录注册" << '\n'; } void footer() { cout << "帮助中心,交流合作" << '\n'; } void left() { cout << "jave,pythhon" << '\n'; } }; class java:public bage { public: void content() { cout << "java学科视屏" << '\n'; }
}; class python :public bage { public: void content() { cout << "python学科视屏" << '\n'; } };
void test01() { java ja; ja.header(); ja.footer(); ja.left(); ja.content(); cout << "-------------" << '\n'; python py; py.header(); py.footer(); py.left(); py.content();
} int main() { test01(); return 0; }
|
继承方式有三种
1.公共继承
2.保护继承
3.私有继承
每一个子类都无法访问父类的私有成员,然后相关的继承方式决定了继承后的成员
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
| #include<iostream> using namespace std; class bage { public: int m_a; protected: int m_b; private: int m_c; }; class son :public bage { public: void func() { m_a = 100; m_b = 100; } }; void test01() { son a; a.m_a = 100; } class son1 :protected bage { public: void func() { m_a = 100; m_b = 100; } }; void test02() { son1 a1; } class son1 :private bage { public: void func() { m_a = 100; m_b = 100; } }; void test03() { son1 a1; } int main() { }
|
存储规则
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
| #include<iostream> using namespace std; class bage { public: int m_a; protected: int m_b; private: int m_c; }; class son :public bage { public: int m_d; }; void test01() { cout << sizeof son; } int main() { test01(); }
|
输出结果是16
继承中构造和析构的顺序
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
| #include<iostream> using namespace std; class bage { public: bage() { cout << "构造" << '\n'; } ~bage() { cout << "析构" << '\n'; } }; class son :public bage { public: son() { cout<< "son的构造" << '\n'; } ~son() { cout << "son的析构" << '\n'; } }; void test01() { son p1; } int main() { test01(); }
|
输出结果:
构造 son的构造 son的析构 析构
顺序如下:先构造父类,再子类,析构相反
继承同名成员的处理方式
当子类与父类出现同名成员,如何通过子类对象,访问子类或父类中同名的成员
访问子类同名成员:直接访问
访问父类成员:需要加作用域
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
| #include<iostream> using namespace std; class bage { public: int m_a; bage() { m_a = 100; } }; class son :public bage { public: son() { m_a = 200; } int m_a; }; void test01() { son s; cout << s. m_a<<'\n'; cout << s.bage::m_a; } int main() { test01(); 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
| #include<iostream> using namespace std; class bage { public: static int m_a; }; int bage::m_a = 100;
class son :public bage { public: static int m_a; }; int son::m_a = 200;
void test01() { son s; cout << s.m_a << '\n'; cout << s.bage::m_a<<'\n'; cout << son::m_a << '\n'; cout << son::bage::m_a; }
int main() { test01(); }
|
多继承语法
作用域也需要
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
| #include<iostream> using namespace std; class bage1 { public : bage1() { m_a = 100; }
int m_a; }; class bage2 { public: bage2() { m_a = 200; } int m_a; }; class son :public bage1, public bage2 { public: son() { m_c = 100; m_d = 100; } int m_c; int m_d; }; void test01() { son s; cout << sizeof(s)<<'\n'; cout << s.bage1::m_a<<'\n'; cout << s.bage2::m_a; } int main() { test01();
}
|
菱形继承
1 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
| #include<iostream> using namespace std; class animal { public: int m_age; }; class sheep :virtual public animal {
}; class yang :virtual public animal {
}; class yangtuo : public yang, public sheep {
}; void test01() { yangtuo yangtuoo; yangtuoo.m_age = 10; cout << yangtuoo.m_age; } int main() { test01(); }
|
9.多态
多态是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 26 27 28 29 30 31 32 33
| #include<iostream> using namespace std; class Animal { public: virtual void speak() { cout << "动物在说话" << '\n'; } }; class Cat :public Animal { public:
void speak() { cout << "小猫在说话" << '\n'; } }; void dospeak(Animal& animal) { animal.speak(); } void test01() { Cat cat; dospeak(cat); } int main() { test01(); }
|
多态优势
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
| #include<iostream> using namespace std;
class calculateor { public: int getresulr(string oper) { if (oper == "+") { return m_num1 + m_num2; } else if (oper == "-") { return m_num1 - m_num2; } else { return m_num1 *m_num2; }
} int m_num1; int m_num2;
}; void test01() { calculateor c; c.m_num1 = 1; c.m_num2 = 2; cout << c.m_num1 << "+" << c.m_num2 << "=" << c.getresulr("+") << '\n'; cout << c.m_num1 << "-" << c.m_num2 << "=" << c.getresulr("-") << '\n'; cout << c.m_num1 << "*" << c.m_num2 << "=" << c.getresulr("*") << '\n'; }
class abstrat { public: int m_num1; int m_num2; virtual int getresult() { return 0; } }; class addcalculator :public abstrat { public: virtual int getresult() { return m_num1 + m_num2; } }; class jiancalculator :public abstrat { public: virtual int getresult() { return m_num1 - m_num2; } }; class chencalculator :public abstrat { public: virtual int getresult() { return m_num1 * m_num2; } }; void test02() { abstrat* abc=new addcalculator; abc->m_num1 = 10; abc->m_num2 = 10; cout << abc->getresult()<<'\n'; delete abc; } int main() { test02(); }
|
纯虚函数和抽象类
多态中,父类是无用的,是子类发挥作用,因此可以把virtual写成纯虚函数
抽象类无法实例化对象
如果写了抽象类,子类需要重写抽象类的纯虚函数,不然也是抽象类
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
| #include<iostream> using namespace std; class base { public: virtual void func() = 0; }; class son : public base { public: virtual void func() { cout << "i love you"; } }; void test01() { son s; base* basg = new son; basg->func(); } int main() { test01(); }
|
多态案例
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
| #include<iostream> using namespace std; class abstractdrinking { public: virtual void boil() = 0; virtual void brew() = 0; virtual void pour() = 0; virtual void putsome() = 0; void makedrink() { boil(); brew(); pour(); putsome(); } }; class caffee:public abstractdrinking { virtual void boil() { cout << "煮农夫山泉" << '\n'; } virtual void brew() { cout << "冲泡咖啡" << '\n'; } virtual void pour() { cout << "倒入杯中" << '\n'; } virtual void putsome() { cout << "加入糖和牛奶" << '\n'; }
}; class tea :public abstractdrinking { virtual void boil() { cout << "煮开水" << '\n'; } virtual void brew() { cout << "冲泡茶叶" << '\n'; } virtual void pour() { cout << "倒入杯中" << '\n'; } virtual void putsome() { cout << "加入柠檬枸杞" << '\n'; } }; void dowork(abstractdrinking *abs) { abs->makedrink(); delete abs; } void test01() { dowork(new caffee); cout << "-------------" << '\n'; dowork(new tea); } int main() { test01(); 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
| #include<iostream> #include<algorithm> #include<string> using namespace std;
class animal { public: animal() { cout << "animal的构造函数" << '\n'; } ~animal() { cout << "animal的析构函数" << '\n'; } virtual void speak() = 0; }; class cat :public animal { public: cat(string name) { cout << "cat的构造函数" << '\n'; m_name = new string(name); } ~cat() { if (m_name != NULL) { cout << "析构函数的调用" << '\n'; delete m_name; m_name = NULL; } } virtual void speak() { cout <<*m_name<< "笑猫在说话" << '\n'; } string* m_name; }; void test01() { animal* animal = new cat("汤姆"); animal->speak(); delete animal; } int main() { test01();
}
|
上面代码没有走子类的析构代码,所以有问题。
输出
1 2 3 4
| animal的构造函数 cat的构造函数 汤姆笑猫在说话 animal的析构函数
|
解决方案一:虚析构
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
| #include<iostream> #include<algorithm> #include<string> using namespace std;
class animal { public: animal() { cout << "animal的构造函数" << '\n'; } virtual ~animal() { cout << "animal的析构函数" << '\n'; } virtual void speak() = 0; }; class cat :public animal { public: cat(string name) { cout << "cat的构造函数" << '\n'; m_name = new string(name); } ~cat() { if (m_name != NULL) { cout << "析构函数的调用" << '\n'; delete m_name; m_name = NULL; } } virtual void speak() { cout <<*m_name<< "笑猫在说话" << '\n'; } string* m_name; }; void test01() { animal* animal = new cat("汤姆"); animal->speak(); delete animal; } int main() { test01();
}
|
解决方案二:纯虚析构
需要声明也需要实现
有了纯虚析构,也属于抽象类,无法实例化对象
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
| #include<iostream> #include<algorithm> #include<string> using namespace std;
class animal { public: animal() { cout << "animal的构造函数" << '\n'; } virtual ~animal() = 0; virtual void speak() = 0; }; animal:: ~animal() { cout << "纯虚析构" << '\n'; } class cat :public animal { public: cat(string name) { cout << "cat的构造函数" << '\n'; m_name = new string(name); } ~cat() { if (m_name != NULL) { cout << "析构函数的调用" << '\n'; delete m_name; m_name = NULL; } } virtual void speak() { cout <<*m_name<< "笑猫在说话" << '\n'; } string* m_name; }; void test01() { animal* animal = new cat("汤姆"); animal->speak(); delete animal; } int main() { test01();
}
|
多态案例:纯虚析构
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
|
#include<iostream> using namespace std; class cpu { public: virtual void calculate() = 0; }; class videocard { public: virtual void display() = 0; }; class meomry { public: virtual void store() = 0; }; class computer { public: computer(cpu *_cpu1,videocard *_vc,meomry *_meo) { cpu1 = _cpu1; vc1 = _vc; meo = _meo; } void work() { cpu1->calculate(); vc1->display(); meo->store(); } ~computer() { if (cpu1 != NULL) { delete cpu1; cpu1 = NULL; } if (vc1 != NULL) { delete vc1; vc1 = NULL; } if (meo != NULL) { delete meo; meo = NULL; }
} private: cpu* cpu1; videocard* vc1; meomry* meo; };
class intelcpu :public cpu { virtual void calculate() { cout << "intel的cpu开始工作了" << '\n'; } }; class intelvideo :public videocard { virtual void display() { cout << "intel的显卡开始工作了" << '\n'; } }; class intelmeomry :public meomry { virtual void store() { cout << "intel的显卡开始工作了" << '\n'; } }; void test01() { cpu* m_intelcpu = new intelcpu; videocard* m_intelcard = new intelvideo; meomry* m_intelme = new intelmeomry; computer* computer1 = new computer(m_intelcpu, m_intelcard, m_intelme); computer1->work(); delete computer1; } int main() { test01(); }
|
文件操作
程序产生的数据都属于临时数据,程序一旦运行起来都会被释放,通过文件可以将数据持久化
C++文件对文件操作需要饱.
文件类型分为两种
第一种是文本文件,文件以文本的 ASCLL 的形式存储在计算机种
第二种是二进制文件,以二进制文件存储在计算机种,用户一般不能直接读懂他们
操作文件有三大类:
- :写
- :读
- :读写操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| 写文件操作: 1.包含头文件
<fstream>
2.创建流对象 ofstream ofs
3.打开文件 ofs.open("文件路径",打开方式)
4.写数据 ofs<<"写入的数据";
5.关闭文件 off.close();
|
1 2 3 4 5 6 7 8
| 文件打开方式 1.ios::in 读 2.ios::out 写 3.ios:: ate 文件尾部 4.ios::app 追加方式 4.ios::tunc 如果文件存在先删除,再创建 5.ios::binary 二进制方式 注意可以配合使用,使用|即可
|
写文件
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
| #include<iostream>
#include<fstream> using namespace std; void test01() { ofstream ofs;
ofs.open("test.txt", ios::out);
ofs << "姓名:张三" << '\n'; ofs << "年龄:18" << '\n';
ofs.close(); } int main() { test01(); }
|
读文件
读文件与写文件相似,读取方式相对多样
读文件的步骤如下::
1.包含头文件:#include
2.创建流对象
3.打开文件,并判断文件是否打开成功
4.读数据
4种方式进行读取
5.关闭文件
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
| #include<iostream> #include<ostream>
#include<fstream> using namespace std; void test01() { ofstream ofs;
ofs.open("test.txt", ios::out);
ofs << "姓名:张三" << '\n'; ofs << "年龄:18" << '\n';
ofs.close(); ifstream ifs; ifs.open("test.txt", ios::in); if (!ifs.is_open()) { cout << "文件打开失败" << '\n'; return; }
string buf; while ( getline(ifs,buf) ) { cout << buf; } char c; while((c=ifs.get())!=EOF) { cout<<c; } }
int main() { test01(); 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
| #include<bits/stdc++.h>
using namespace std; class Person { public: char m_name[64]; int m_age; }; void test01() { ofstream ofs; ofs.open("person.txt",ios::out|ios::binary); Person p={"张三",19}; ofs.write((const char *)&p,sizeof(Person)); ofs.close(); } int main() { test01(); 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
| #include<bits/stdc++.h>
using namespace std; class Person { public: char m_name[64]; int m_age; }; void test01() { ifstream ifs; ifs.open("person.txt",ios::in|ios::binary); if(!(ifs.is_open())) { cout<<"打开失败了"<<'\n'; return ; } Person p; ifs.read((char *)&p,sizeof(Person)); cout<<p.m_name<<'\n'; cout<<p.m_age; ifs.close(); } int main() { test01(); return 0; }
|