一、大于运算符重载
#include <iostream> using namespace std; class Student { public: Student(string n, int i, float s) { this->id = i; this->name = n; this->scored = s; } bool operator>(Student &s) { if (this->scored > s.scored) { return true; } else { return false; } } private: string name; int id; float scored; }; int main() { Student s1("bb", 10, 99); Student s2("cb", 0, 59); if (s1 > s2) { cout << "bb六" << endl; } else { cout << "cb六" << endl; } return 0; }
二、关系运算符重载
#include <iostream> using namespace std; class Person { public: Person(string name, int age) { this->m_name = name; this->m_age = age; } int m_age; string m_name; bool operator==(Person &p) { if (this->m_name == p.m_name && this->m_age == p.m_age) { return true; } else { return false; } } bool operator!=(Person &p) { if (this->m_name == p.m_name && this->m_age == p.m_age) { return false; } else { return true; } } }; int main() { Person p1("qq", 18); Person p2("qq", 18); if (p1 == p2) { cout << "p1=p2" << endl; } else { cout << "p1!=p2" << endl; } if (p1 != p2) { cout << "p1!=p2" << endl; } else { cout << "p1=p2" << endl; } return 0; }
三、赋值运算符重载
C++会至少给一个类添加4个函数:
1默认构造函数、
2.默认析构函数、
3.默认拷贝构造函数(对属性进行一个值拷,浅拷贝)
4.赋值运算符重载函数operator(对属性进行值拷贝、浅拷贝),
#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) { //m_Age = p.m_Age; //编译器默认做的就是这句话。(浅拷贝) if(m_Age != NULL) //自己提供深拷贝。 { delete m_Age; m_Age = NULL; } m_Age = new int(*p.m_Age); return *this; } int *m_Age; }; int main() { /* Person p1("张三",18); cout << "p1的姓名:" << p1.m_Name << " 年龄:" << p1.m_Age << endl; Person p2 = p1; cout << "p2的姓名:" << p2.m_Name << " 年龄:" << p2.m_Age << endl; */ Person p3(18); Person p4(20); //有参构造函数 //Person p4 = p3; //拷贝构造函数(默认就是浅拷贝),我不调用重载函数 Person p5(30); p5 = p4 = p3; //如果有连等的操作,以引用的方式来将对象返回。 cout << "p3的年龄:" << *p3.m_Age << endl; cout << "p4的年龄:" << *p4.m_Age << endl; cout << "p5的年龄:" << *p5.m_Age << endl; return 0; }
结论:
1.只要有属性开辟到堆区,那么使用对象给另一个对象赋值时,必须自己重新写operate这个重载函数来投共深拷贝
四、函数调用运算符重载
1.函数运算符()也是可以重载的
2、由于重载以后使用方法非常像函数的调用,因此称为仿函数
3.仿函数没有固定的写法,非常的灵活
#include <iostream> using namespace std; //函数调用运算符重载。 //设计打印类。 class Myprint{ public: //重载函数调用运算符 void operator()(string text) { cout << text << endl; } }; //设计加法类 class Myadd{ public: int operator()(int num1,int num2) { return num1 + num2; } }; void myint02(string text) { cout << text << endl; } int main() { //Myprint myint; //m.operator()("helloworld"); //myint("helloworld"); //由于重载之后使用方式非常像函数的调用,因此称为仿函数。 //myint02("helloworld"); Myadd ma; //int ret = ma.operator()(10,20); //int ret = ma(10,20); //cout << "ret = " << ret << endl; //30 cout << ma(10,20) << endl; //30 cout << Myadd()(10,20) << endl; //30 //Myadd() -> 无名函数对象 Myadd()(10,20); //ma -> 有名函数对象 ma(10,20); return 0; }
五、继承
继承是面向对象三大特性之一。
有一些类与类之间存在一些特殊的关系,
例如: 有一个动物类,猫与狗都是属于动物,都有动物的共性,也有自己的个性。
我们发现,定义这些类的时候,下级的成员除了拥有上一级的共性,还有自己的特性。
这个时候我们就可以考虑利用继承的技术,减少重复的代码。
六、继承
案例:例如我们考到很多网页,都是由公共的头部、公共的底部,只有中心的内容不一样
子类也称为派生类,父类也称为基类
//继承语法:
//class 子类:继承方式 父类
//继承的好处:
//减少重复的代码
#include <iostream> using namespace std; //继承写法 -- 共性 class BasePage { public: void head() { cout << "网址、书签、搜索栏、菜单栏、" << endl; } void right() { cout << "专题推荐" << endl; } void footer() { cout << "评论区、发帖子" << endl; } }; //继承语法: //class 子类:继承方式 父类 class Page_one : public BasePage { public: void content() { cout << "向袁隆平学习" << endl; } }; class Page_two : public BasePage { public: void content() { cout << "从不哪一个红薯" << endl; } }; class Page_three : public BasePage { public: void content() { cout << "马拉松遇难" << endl; } }; int main() { cout << "第一个网页内容图下" << endl; Page_one po; po.head(); po.right(); po.content(); po.footer(); cout << "第二个网页内容图下" << endl; Page_two pt; pt.head(); pt.right(); pt.content(); pt.footer(); cout << "第三个网页内容图下" << endl; Page_three ps; ps.head(); ps.right(); ps.content(); ps.footer(); return 0; }
七、继承方式
继承语法:
class 子类:继承方式 父类
继承方式:
①公共继承
②保护继承
③私有继承
、
#include <iostream> using namespace std; //继承方式 //公共继承 class Base1{ public: int m_A; protected: int m_B; private: int m_C; }; class Son1:public Base1{ //公共继承 public: void func() { m_A = 10; //公共属性 -> 公共属性(类内可以访问公共属性) m_B = 20; //保护属性 -> 保护属性(类内可以访问保护属性) //m_C = 30; //私有属性 -> 不可以访问 } }; //保护继承 class Base2{ public: int m_A; protected: int m_B; private: int m_C; }; class Son2:protected Base2{ //保护继承 public: void func() { m_A = 100; //公共属性 -> 保护属性(类内可以访问保护属性) m_B = 200; //保护属性 -> 保护属性(类内可以访问保护属性) //m_C = 300; //私有属性 -> 不可以访问 } }; class GrandSon2:public Son2{ public: void func() { m_A = 50; //保护属性 -> 保护属性(类内可以访问保护属性) m_B = 50; //保护属性 -> 保护属性(类内可以访问保护属性) } }; //私有继承 class Base3{ public: int m_A; protected: int m_B; private: int m_C; }; class Son3:private Base3{ public: void func() { m_A = 100; //公共属性 -> 私有属性(类内可以访问) m_B = 200; //保护属性 -> 私有属性(类内可以访问) //m_C = 300; //私有属性 -> 不可以访问。 } }; class GrandSon3:public Son3{ public: void func() { //m_A = 100; //私有属性 -> 不可以访问 //m_B = 100; //私有属性 -> 不可以访问 } }; int main() { Son1 s1; s1.m_A = 100; //公共属性 -> 公共属性(类外可以访问公共属性) //s1.m_B = 200; //保护属性 -> 保护属性(类外不可以访问保护属性) //s1.m_C = 300; //私有属性 -> 不可以访问 Son2 s2; //s2.m_A = 100; //公共属性 -> 保护属性(类外不可以访问保护属性) //s2.m_B = 200; //保护属性 -> 保护属性(类外不可以访问保护属性) //s2.m_C = 300; //私有属性 -> 不可以访问 Son3 s3; //s3.m_A = 100; //公共属性 -> 私有属性(类外不可以访问) //s3.m_B = 200; //保护属性 -> 私有属性(类外不可以访问) //s3.m_C = 300; //私有属性 -> 不可以访问。 return 0; }
八、继承中的对称模型
问题:从父类中继承过来的成员,那些是属于子类对象上的?
#include <iostream> using namespace std; class Base { public: int m_a; protected: int m_b; private: int m_c; }; class son : public Base { public: int m_d; }; int main() { //1.计算父类对象的大小 cout << "sizeof(Base)" << sizeof(Base) << endl; //父类中所有的非静态成员属性都会被子类继承下来。 //父类的私有成员属性是被编译器隐藏了,因此访问不到,但它确实是继承下来了 cout << "sizeof(son)" << sizeof(son) << endl; return 0; }
结论;
//父类中所有的非静态成员属性都会被子类继承下来。
//父类的私有成员属性是被编译器隐藏了,因此访问不到,但它确实是继承下来了
九、继承构造函数与析构的顺序?
子类继承父类以后。当创建子类对象时,
父亲先构造,子类再构造,析构则是相反
继承中构造与析构的顺序
#include <iostream> using namespace std; class Base { public: Base() { cout << "Base构造" << endl; } ~Base() { cout << "Base析构" << endl; } }; class Son : public Base { public: Son() { cout << "son构造" << endl; } ~Son() { cout << "son析构" << endl; } }; int main() { Base b; Son s; return 0; }
十、继承中同名成员的处理方式
问题:当子类中与父类出现同名的成员,如何通过子类对象访问子类或者是父类中同名的数据
#include <iostream> using namespace std; //继承中同名成员处理方式 //1)访问子类同名成员,直接访问就可以了。 //2)访问父类同名成员,需要加作用域。 //设计父类 class Base{ public: Base() { m_A = 10; //非静态成员属性 } void func() //非静态成员函数 { cout << "Base - func函数调用" << endl; } int m_A; }; class Son:public Base{ public: Son() { m_A = 20; } void func() //非静态成员函数 { cout << "Son - func函数调用" << endl; } int m_A; //非静态成员属性 }; int main() { //1. 同名成员属性处理方式。 //Son s; //实例化子类的对象,就会先调用父类的构造函数,再调用子类的构造函数。 //cout << "Son下的m_A = " << s.m_A << endl; //子类对象访问子类成员,直接访问就可以了。 //cout << "Base下的m_A = " << s.Base::m_A << endl; //子类对象访问父类成员,需要加作用域。 //2. 同名成员函数处理。 Son s; s.func(); //直接调用,则调用的是子类中同名成员。 s.Base::func(); //加作用域,则访问的是父类的函数。 return 0; }
结论:
//访问子类同名成员,直接访问就可以了,
//访问父类同名成员,需要加作用域
十一、继承中同名的静态成员的处理方式。
问题:继承中同名的静态成员在子类中是如何访问的
静态成员与非静态成员出现同名情况。处理方式以一致
1)访问子类中静态成员,直接访问即可、
2)访问父类中静态成员函数,前面添加作用域
#include <iostream> using namespace std; class Base { public: static int m_a; static void func() { cout << "base - static void func()" << endl; } }; int Base::m_a = 100; class Son : public Base { public: static int m_a; static void func() { cout << "son - static void func()" << endl; } }; int Son::m_a = 200; int main() { //计算子类对象的大小 cout << sizeof(Son) << endl; //通过对象访问 Son s; cout << s.m_a << endl; cout << s.Base::m_a << endl; //通过类名访问 cout << Base::m_a << endl; cout << Son::m_a << endl; //通过对象访问 s.func(); s.Base::func(); //通过类名访问 Son::func(); Base::func(); Son::Base::func(); return 0; }
十二、多继承的语法(不推荐使用,可能会很麻烦,和别人合作不方便)
C++中允许一个类继承多个类
语法: class 子类:继承方式 父类1,继承方式 父类二…………
多继承可能会引起父类中同名成员出现,需要加作用域加以区分
#include <iostream> using namespace std; class Base1 { public: Base1() { m_a = 100; } int m_a; }; class Base2 { public: Base2() { m_a = 200; } int m_a; }; //class 子类:继承方式 父类1,继承方式 父类二………… class Son : public Base1, public Base2 { public: Son() { m_c = 300; m_d = 400; } int m_c; int m_d; }; int main() { cout << sizeof(Son) << endl; //当名字不同时访问如下 Son s; cout << s.Base1::m_a << endl; cout << s.Base2::m_a << endl; cout << s.m_c << endl; cout << s.m_d << endl; return 0; }