03 面向对象
1、封装
1.1 属性和行为
#include <iostream>
using namespace std;// 面向对象三大特性:封装、继承、多态/*
封装的语法:class 类名 {
访问权限:属性(成员变量)行为(成员函数)
};
*/class Hero {// 访问权限 public private protected
public:// 属性int m_Id; // m -> memberint m_Hp;// 行为void addHp(int hp) {m_Hp += hp;}void subHp(int hp) {m_Hp -= hp;}
};int main() {// 通过类来生成对象的过程,叫 实例化Hero h;// 访问对象的属性h.m_Id = 5;h.m_Hp = 100;h.addHp(100);cout << "Id 为" << h.m_Id << "的英雄,血量是" << h.m_Hp << endl;h.subHp(100);cout << "Id 为" << h.m_Id << "的英雄,血量是" << h.m_Hp << endl;return 0;
}
1.2 访问权限
#include <iostream>
using namespace std;/*
访问权限
公共权限 public 类内可以访问,类外也可以访问
保护权限 protected 类内可以访问,类外不可以访问 子类可以访问
私有权限 private 类内可以访问,类外不可以访问 子类不可以访问(继承)B -> AA 父类、基类 名字、房子、支付密码
B 子类、派生类 公有、保护、私有*/class People {// 公有权限
public:int m_Id;// 保护权限
protected:int m_HouseId;// 私有权限
private:int m_PayPass;public:void work() {// 所有成员变量,类内均可以访问m_Id = 1;m_HouseId = 2;m_PayPass = 1314;}
private:void work1() {// 所有成员变量,类内均可以访问m_Id = 1;m_HouseId = 2;m_PayPass = 1314;}};class Son : public People {void func() {m_Id = 1;m_HouseId = 4; // 保护成员,子类可以访问// m_PayPass = 123; // 私有成员,子类无法访问People::work();// People::work1();//私有成员,子类无法访问}
};int main() {// 实例化People p;p.m_Id = 1; // 公有成员,类外可以访问//p.m_HouseId = 5; // 保护成员,类外不可以访问//p.m_PayPass = 10; // 私有成员,类外不可以访问p.work();// p.work1(); // 私有成员函数,类外不可访问return 0;
}
1.3class和struct
#include <iostream>
using namespace std;/*
struct && classstruct 默认是公共的
class 默认是私有的
*/class C {int m_a;
};struct S {int m_a;void func() { //c和c++区别 c不能定义函数m_a = 666;}
};int main() {C c;S s;// c.m_a; // 私有的s.m_a = 4; // 公有的s.func();cout << s.m_a << endl;//666return 0;
}
1.4 属性私有化
#include <iostream>
#include <string>
using namespace std;// 接口、方法、函数 是同一个概念
// 1、可以控制读写权限
// 2、可以检测数据的有效性class Hero {
public://方法来访问属性成员变量void SetName(string name) { //设置m_Name = name;}string GetName() { //获取return m_Name;}int GetSkillCount() {return m_SkillCount;}void SetSpeed(int speed) { //设置if (speed < 100 || speed > 500) {cout << "速度设置不合法" << endl;return;}m_Speed = speed;}private:string m_Name; // 可读,可写int m_SkillCount = 4; // 只读int m_Speed; // 只写
};int main() {Hero h;/* 不行,访问不了h.m_Name = "123";h.m_SkillCount = 4;h.m_Speed = 10;*/h.SetName("剑圣");cout << "英雄的名字叫:" << h.GetName() << endl;cout << "英雄的技能数是:" << h.GetSkillCount() << endl;h.SetSpeed(666);return 0;
}
2、对象特性
2.1构造函数
#include <iostream>
#include <string>
using namespace std;/*
构造函数需要注意的点1、函数名称和类名保持一致
2、返回值类型 不需要写
3、构造函数可以有参数
*/
class Hero {
public:// 默认构造函数/* Hero() {m_Name = "";m_SkillCount = 4;m_Speed = 100;cout << "默认构造函数:Hero 构造完毕!" << endl;}*/// 有参构造函数1Hero(string name="123") { //加了"123" Hero h1;也调用m_Name = name;m_SkillCount = 4;m_Speed = 100;cout << "有参构造函数1:Hero 构造完毕!" << endl;}// 有参构造函数2Hero(string name , int skillCount) {m_Name = name;m_SkillCount = skillCount;m_Speed = 100;cout << "有参构造函数2:Hero 构造完毕!" << endl;}private:string m_Name;int m_SkillCount;int m_Speed;
};int main() {Hero h1;Hero h2("剑圣");Hero h3(); // 函数声明 像int main(); int work(); 没调任何构造函数Hero h4{};Hero h5 = Hero("剑圣");Hero h6{ "猴子", 4 };return 0;
}
/*
默认构造函数:Hero 构造完毕!
有参构造函数1:Hero 构造完毕!
默认构造函数:Hero 构造完毕!
有参构造函数1:Hero 构造完毕!
有参构造函数2:Hero 构造完毕!
*/
2.2析构函数
#include <iostream>
using namespace std;/*
析构函数注意点1、函数名称和类名一致,并且在最前面加上一个 ~ 波浪号
2、函数返回值不需要写
3、不能有参数*/
class Hero {
public:// 构造函数 对象创建Hero() {cout << "Hero 默认构造函数调用完毕!" << endl;}// 析构函数 对象销毁~Hero() {cout << "Hero 析构函数调用完毕!" << endl;}
};void test() {Hero h;
}int main() {test();Hero h;int a;cin >> a;return 0;
}
/*
Hero 默认构造函数调用完毕!
Hero 析构函数调用完毕!
Hero 默认构造函数调用完毕!
12
Hero 析构函数调用完毕!
*/
2.3拷贝构造函数
#include <iostream>
using namespace std;/*
拷贝构造函数的定义
类名(const 类型& 变量名) {}*/
class Hero {
public:// 默认构造函数Hero() {m_Hp = 100;cout << "Hero 默认构造函数调用完毕!" << endl;}// 有参构造函数Hero(int hp) {m_Hp = hp;cout << "Hero 有参构造函数调用完毕!" << endl;}//拷贝构造函数Hero(const Hero& h) {// h.m_Hp = 4;//不可以m_Hp = h.m_Hp;cout << "Hero 拷贝构造函数调用完毕!" << endl;}// 析构函数~Hero() {cout << "Hero 析构函数调用完毕!" << endl;}private:int m_Hp;
};/*
拷贝构造函数的调用时机1、用已经创建的对象来初始化对象
2、函数的传参
3、函数的返回值*/// 1、用已经创建的对象来初始化对象
void func1() {cout << "--------------func1--------------" << endl;Hero h1(20);Hero h2(h1);
}// 2
void test1(Hero h) {}void test2(Hero* h) {}// 2、函数的传参
void func2() {cout << "--------------func2--------------" << endl;Hero h1;// test1(h1);//调拷贝test2(&h1);//传指针,没有生成对象,不调用拷贝
}// 3、函数的返回值
Hero test3() {Hero h(40);return h;
}void func3() {cout << "--------------func3--------------" << endl;Hero h = test3(); //会优化,不调用拷贝构造函数, //解决:右键点击属性->c/c++->命令行 /Zc:nrvo-
}int main() {func1();func2();func3();return 0;
}
2.4初始化列表
#include <iostream>
#include <string>
using namespace std;/*
初始化列表的语法构造函数(传参1, 传参2): 成员变量1(传参1), 成员变量2(传参2) {}*/
class Hero {
public:/*Hero(string name, int hp) {m_Name = name;m_Hp = hp;}*/Hero(string name, int hp, int speed) : m_Name(name), m_Hp(hp), m_Speed(speed) {}void Print() {cout << "英雄:" << m_Name << "的血量是" << m_Hp << ",速度是" << m_Speed << endl;}private:string m_Name;int m_Hp;int m_Speed;
};
int main() {Hero h("剑圣", 100, 10);h.Print();return 0;
}
2.5静态成员变量
#include <iostream>
#include <string>
using namespace std;/*
静态成员变量的特点:
1、所有的对象共享同一份数据
2、编译阶段分配内存
3、需要在类中进行声明,在类外进行初始化
*/
class Hero {
public:Hero() {m_Name = "英雄";m_Hp = 100;}~Hero() {}// 3.1 声明static int m_HeroCount;
private:string m_Name;int m_Hp;};// 3.2 初始化
int Hero::m_HeroCount = 100;//作用域 Hero::int main() {Hero h;cout << h.m_HeroCount << endl;//1 100h.m_HeroCount = 101;cout << Hero::m_HeroCount << endl;//2 101cout << &(h.m_HeroCount) << endl;//00007FF6BC742000cout << &(Hero::m_HeroCount) << endl;//00007FF6BC742000 同一个变量return 0;
}
2.6静态成员函数
#include <iostream>
#include <string>
using namespace std;/*
静态成员函数
1、所有对象共享函数
2、静态成员函数只能使用静态成员变量,无法使用普通成员变量
*/class Hero {
public:Hero() {m_Name = "英雄";m_Hp = 100;}~Hero() {}static int m_HeroCount;static int GetHeroCount() { //静态成员函数//m_Hp += 1;return m_HeroCount;}
private:string m_Name;int m_Hp;static int GetHeroCount1() {// m_Hp += 1;return m_HeroCount;}
};int Hero::m_HeroCount = 100;int main() {Hero h;cout << h.GetHeroCount() << endl;cout << Hero::GetHeroCount() << endl;//h.GetHeroCount1();//拿不了return 0;
}
2.7 this指针
#include <iostream>
using namespace std;/*
this指针
1、解决命名冲突
2、*this 就可以获取到这个对象本身this *this&h *(&h) == h*/class Hero {
public:Hero(int hp) {//hp = hp;//形参覆盖实参this->hp = hp;cout << this << endl;//地址 000000BFDDF1F984cout << (*this).hp << endl;//100}int hp;
};int main() {Hero h(100);cout << h.hp << endl;//100cout << &h << endl; //000000BFDDF1F984 一样cout << (*(&h)).hp << endl;//100return 0;
}
2.8 const修饰成员函数
#include <iostream>
#include <vector>
using namespace std;// 常函数class Hero {
public:Hero() : m_Hp(0) {}int getHp() const {// m_Hp = m_Hp + 1;//无法修改成员变量的值return m_Hp;}int setHp(int hp) {m_Hp = hp;}
private:int m_Hp;
};int main() {const Hero h;//不能被修改// h.setHp(100);//常量不能调用非常量函数h.getHp();return 0;
}
2.9 mutable关键字
#include <iostream>
using namespace std;// mutable 可变 <-> constclass Hero {
public:Hero() :m_Hp(0), m_getHpCounter(0) {}int getHp() const {m_getHpCounter++;return m_Hp;}void printCounter() const {cout << "Counter: " << m_getHpCounter << endl;}private:int m_Hp;mutable int m_getHpCounter;//const函数里可操作
};int main() {Hero h;h.getHp(), h.getHp(), h.getHp(), h.getHp(), h.getHp(), h.getHp();//调6次h.printCounter();return 0;
}
3、友元
3.1全局函数作为友元
#include <iostream>
#include <string>
using namespace std;/*
友元的目的让一个类 或者 函数
能够访问另一个类的私有成员友元的关键字: friend三种友元
1、全局函数作为友元
2、类作为友元
3、成员函数作为友元
*/class People {friend void friendVisit(People* p);
public:People() {m_House = "别墅";m_Car = "跑车";}
public:string m_House;private:string m_Car;
};void friendVisit(People* p) {cout << "好朋友来访问你的" << p->m_House << endl;cout << "好朋友来访问你的" << p->m_Car << endl;//私有成员访问
}int main() {People p;friendVisit(&p);return 0;
}
3.2类作为友元
#include <iostream>
using namespace std;// 类作为友元
// 让一个类去访问另一个类的私有成员class People;//声明class PeopleFriend {
public:PeopleFriend() {}void visit(People* p);/*void visit(People* p) {cout << "好朋友来访问你的" << p->m_House << endl;cout << "好朋友来访问你的" << p->m_Car << endl;//m_House,m_Car 还没执行到,不知道,放在后面实现}*/
};class People {friend class PeopleFriend;//访问私有
public:People() {m_House = "别墅";m_Car = "跑车";}
public:string m_House;private:string m_Car;
};//函数实现
void PeopleFriend::visit(People* p) {cout << "好朋友来访问你的" << p->m_House << endl;cout << "好朋友来访问你的" << p->m_Car << endl;
}int main() {People p;PeopleFriend pf;pf.visit(&p);return 0;
}
3.3成员函数作为友元
#include <iostream>
#include <string>
using namespace std;// 成员函数作为友元
// PeopleFriend 的某个函数能够访问 People 的私有成员变量class People;class PeopleFriend {
public:PeopleFriend() {}void visitAll(People* p);void visitPub(People* p);
};class People {// friend class PeopleFriend;friend void PeopleFriend::visitAll(People* p);
public:People() {m_House = "别墅";m_Car = "跑车";}
public:string m_House;
private:string m_Car;
};void PeopleFriend::visitAll(People* p) {cout << "好朋友访问了你的" << p->m_House << endl;cout << "好朋友访问了你的" << p->m_Car << endl;}
void PeopleFriend::visitPub(People* p) {cout << "好朋友访问了你的" << p->m_House << endl;//cout << "好朋友访问了你的" << p->m_Car << endl;//不可访问
}int main() {People p;PeopleFriend pf;pf.visitAll(&p);pf.visitPub(&p);return 0;
}
4、运算符重载
4.1概念
参考网址:C++语法——详解运算符重载_c++运算符重载-CSDN博客
#include <iostream>
#include <string> //是一个类using namespace std;/*
+
4 + 5 = 9class A {
};A a;
A b;
a + b;*/
int main() {// 1、加法运算符int a = 520;int b = 1314;cout << a + b << endl;// 2、字符串拼接string c = "520";string d = "1314";cout << c + d << endl;//5201314 运算符重载string e = "我";string f = "爱你";cout << e + f << endl;return 0;
}
4.2 +号重载
重载形式:[返回值] operator[运算符] (参数...) { ... };
#include <iostream>
using namespace std;/*
+
*/
// 复数类
class Complex {friend Complex operator+(Complex& a, Complex& b);friend Complex operator-(Complex& a, Complex& b);
public:Complex() : real(0), image(0) {}Complex(int real, int image) {this->real = real;this->image = image;}//复数相加函数Complex add(Complex& other) { Complex ret;ret.real = this->real + other.real;//this 是 指针 other 是 对象ret.image = this->image + other.image;return ret;}成员函数重载//Complex operator+(Complex& other) {// Complex ret;// ret.real = this->real + other.real;// ret.image = this->image + other.image;// return ret;//}// a + bivoid Print() {cout << real << '+' << image << 'i' << endl;}private:int real;//实部int image;//虚部
};//全局函数重载实现 需要两个对象
Complex operator+(Complex& a, Complex& b) { //引入友元Complex ret;ret.real = a.real + b.real;ret.image = a.image + b.image;return ret;
}Complex operator-(Complex& a, Complex& b) {Complex ret;ret.real = a.real - b.real;ret.image = a.image - b.image;return ret;
}int main() {Complex a(10, 20);Complex b(5, 8);Complex c =a.add(b);c.Print();//15+28i//Complex c = a.operator+(b);//15+28i//Complex c1 = a + b;//函数名变成operator+实现 可以直接实现 成员函数//全局函数Complex c1 = a + b;Complex d = a - b;c1.Print();d.Print();//5+12ireturn 0;
}
4.3 左移重载
#include <iostream>
using namespace std;/*
左移运算符 :<< 把对象输出来Complex c;
cout.operator<<(c) 实现// 成员函数重载
c.operator<<(cout) cout是ostream对象
c << cout 这个不是我们想实现的
*/
// 复数类
class Complex {friend Complex operator+(Complex& a, Complex& b);friend Complex operator-(Complex& a, Complex& b);friend ostream& operator<<(ostream& cout, Complex a);
public:Complex() : real(0), image(0) {}Complex(int real, int image) {this->real = real;this->image = image;}/*Complex operator+(Complex& other) {Complex ret;ret.real = this->real + other.real;ret.image = this->image + other.image;return ret;}*/// a + bivoid Print() {cout << real << '+' << image << 'i' << endl;}private:int real;int image;
};Complex operator+(Complex& a, Complex& b) {Complex ret;ret.real = a.real + b.real;ret.image = a.image + b.image;return ret;
}Complex operator-(Complex& a, Complex& b) {Complex ret;ret.real = a.real - b.real;ret.image = a.image - b.image;return ret;
}//cout重载实现
ostream& operator<<(ostream& cout, Complex a) {//&不会调到拷贝构造函数 只有一个coutcout << a.real << '+' << a.image << 'i';return cout;//要有返回值<< endl才能实现
}int main() {Complex a(10, 20);Complex b(5, 8);// Complex c = a.operator+(b);Complex c = a + b;Complex d = a - b;//c.Print();//d.Print();// operator<<(cout, c)cout << c << endl << endl;//重载来实现Complex c的输出return 0;
}
有delete 任何地方的不能调用cout的拷贝构造函数。
4.4 递增重载
#include <iostream>
using namespace std;/*
++前置 ++
后置 ++
*/class Complex {friend ostream& operator<<(ostream& c, const Complex& a);
public:Complex() : real(0), image(0) {}Complex(int real, int image) { //有参构造函数this->real = real;this->image = image;}Complex& operator++() { //前置 ++this->real += 1;return *this; //返回Complex&,就可以用cout << ++(++a) << endl;}Complex operator++(int) { //后置++ 加一个占位符 且必须是int 类型 Complex c = *this; //要返回另一个对象 this->real += 1;return c;}private:int real;int image;
};//复数的输出
ostream& operator<<(ostream& c, const Complex& a) { //c is coutc << a.real << '+' << a.image << 'i';return c;
}class A {};
A func1() { // 模拟Complex operator++(int)return A();
}
void func2(const A& a) { //模拟ostream& operator<<(ostream& c, const Complex& a)}int main() {int x = 1;cout << ++(++x) << endl;//3cout << x << endl;//3Complex a(10, 10);cout << a << endl;//10+10i// ++a;cout << ++(++a) << endl;//12+10i// cout << a << endl;//11+10i 不加引用时 前置生成另一个对象cout << a << endl;//12+10i 加引用时cout << a++ << endl;//12+10icout << a << endl;//13+10i//func2(func1());//不加const错误 非常量引用的初始值必须为左值// cout << ((a++)++)++ << endl;不可以这样写cout << a << endl;//13+10iint b = 5;// cout << ((b++)++)++ << endl;不可以这样写cout << b << endl;return 0;
}
4,5 赋值重载
#include <iostream>
using namespace std;class Hero {
public:Hero() : m_Data(NULL) {}Hero(int data) {m_Data = new int;//内存申请*m_Data = data;}// 错误:double delete~Hero() {if (m_Data) {//感受内存泄露 if 不重载赋值号:会报错delete m_Data;//一个内存调用两次delete 不行m_Data = NULL;}}//解决Hero& operator=(Hero& h) {// m_Data = h.m_Data;//double free问题if (m_Data) {delete m_Data;m_Data = NULL;}// m_Data=NULL执行m_Data = new int;*m_Data = *h.m_Data;return *this; //h3 = (h2 = h1);实现}int* m_Data;
};int main() {Hero h1(1);Hero h2(2);// if 不重载赋值号// h1 = h2;//h2的m_Data会覆盖h1的m_Data ,内存相同 ,内存泄露Hero h3(3);cout << h1.m_Data << endl;cout << h2.m_Data << endl;h1 = h2; // cout << h1.m_Data << endl;cout << h2.m_Data << endl;h3 = (h2 = h1);cout << h1.m_Data << endl;cout << h2.m_Data << endl;cout << h3.m_Data << endl;return 0;
}
4.6 关系运算符重载
#include <iostream>
using namespace std;class Point { //点类
public:Point(int x, int y) : m_x(x), m_y(y) {}bool operator==(const Point& other) const {//函数const包含m_x 和 m_yreturn m_x == other.m_x && m_y == other.m_y;}bool operator<(const Point& other) const {int d = m_x * m_x + m_y * m_y;int otherd = other.m_x * other.m_x + other.m_y * other.m_y;return d < otherd;}bool operator>(const Point& other) const {if (*this == other) {return false;}if (*this < other) {return false;}return true;}
private:int m_x, m_y;
};int main() {Point a(1, 6);Point b(2, 5);if (a == b) { //一个类==要重载cout << "a 和 b 相等" << endl;}else if (a < b) {cout << "a 比 b 更加接近原点" << endl;}else if (a > b) {cout << "b 比 a 更加接近原点" << endl;//b 比 a 更加接近原点}return 0;
}
4.7 函数调用运算符重载
#include <iostream>
using namespace std;// ()
// add()class AddFunctor {
public:AddFunctor() {m_acc = 0;}int operator() (int a, int b) {m_acc++;return a + b + m_acc;}
private:int m_acc;
};int Add(int a, int b) {return a + b;
}int main() {AddFunctor add;//对象cout << add(5, 6) << endl;//仿函数 cout << add(5, 6) << endl;cout << add(5, 6) << endl; cout << add(5, 6) << endl;cout << add(5, 6) << endl;cout << Add(5, 6) << endl;//每次调用一样cout << Add(5, 6) << endl;cout << Add(5, 6) << endl;cout << Add(5, 6) << endl;cout << Add(5, 6) << endl;//12 13 14 15 16 11 11 11 11 11return 0;
}
5、继承
5.1 继承的语法
#include <iostream>
using namespace std;/*
* 动物
* / \
* 猫 狗
*
* 继承的语法
* class 子类 : 继承方式 父类 {}
* 子类 -> 派生类
* 父类 -> 基类
*/class Animal {
public:void eat() {cout << "吃" << endl; //猫,狗都吃,所以抽象在一个类}
};class Cat : public Animal {
public:void sayHi() {cout << "喵~" << endl;}
};class Dog : public Animal {
public:void sayHi() {cout << "汪汪汪~" << endl;}
};int main() {Cat c;Dog d;c.eat();d.eat();c.sayHi();d.sayHi();return 0;
}
5.2 继承的方式
#include <iostream>
using namespace std;/*
继承方式class 子类名 : 继承方式 父类名 {};公共 public
保护 protected
私有 private3 x 3 = 9父类权限| public | protected | private
子类继承方式public | public | protected | 无法访问protected | protected | protected | 无法访问private | private | private | 无法访问public: 类内可以访问,类外也可以访问
protected: 类内可以访问,类外不可访问,且子类可以访问
private: 类内可以访问,类外不可访问,且子类不可访问
*/class Animal {
public:int m_pub;
protected:int m_pro;
private:int m_pri;
};class Cat : public Animal {
public:Cat() {m_pub = 1;m_pro = 2;// m_pri = 3; 父类私有成员,子类公有继承,无法访问}
};class BossCat : public Cat {
public:BossCat() {m_pub = 1;m_pro = 2; // 父类Cat中不是私有}
};void testCat() {Cat c;c.m_pub = 1;// c.m_pro = 2; // 要么是私有,要么是保护
}//2
class Dog : protected Animal {
public:Dog() {m_pub = 1;m_pro = 2;// m_pri = 3; // 父类私有成员,子类保护继承,无法访问}
};class PoliceDog : public Dog {
public:PoliceDog() {m_pub = 1; // 这个变量,在父类 Dog 中一定不是私有成员m_pro = 2; // 这个变量,在父类 Dog 中一定不是私有成员}
};void testDog() {Dog d;// d.m_pub = 1; // 要么是保护,要么是私有// d.m_pro = 2; // 要么是保护,要么是私有
}//3
class Pig : private Animal {
public:Pig() {m_pub = 1;m_pro = 2;// m_pri = 3; // 父类私有成员,子类私有继承,无法访问}
};class WildPig : public Pig {
public:WildPig() {// m_pub = 1; // 该变量在父类 Pig 中是私有的// m_pro = 2; // 该变量在父类 Pig 中是私有的}
};void testPig() {Pig p;// p.m_pub = 1; // 要么是保护,要么是私有// p.m_pro = 2; // 要么是保护,要么是私有
}int main() {return 0;
}
5.3 构造函数和析构函数顺序
#include <iostream>
using namespace std;/*
继承中,构造链里,先构造的后析构d -> c -> b -> a d继承a..a b c d d c b a
*/class Animal {
public:Animal() {cout << "Animal 构造" << endl;}~Animal() {cout << "Animal 析构" << endl;}
};class Cat : public Animal {
public:Cat() {cout << "Cat 构造" << endl;}~Cat() {cout << "Cat 析构" << endl;}
};class BossCat : public Cat {
public:BossCat() {cout << "BossCat 构造" << endl;}~BossCat() {cout << "BossCat 析构" << endl;}
};void Test() {//Animal a;//Cat c;//先调父类的构造,再调自己BossCat b;
}int main() {Test();return 0;
}
5.4 同名属性的访问
#include <iostream>
using namespace std;//父类和子类变量名相同
class Animal {
public:Animal() {m_Data = 17891;}int m_Data;
};class Cat : public Animal {
public:Cat() {m_Data = 29812;}int m_Data;
};void Test() {Cat c;cout << c.m_Data << endl;//29812cout << c.Animal::m_Data << endl;//17891cout << &(c.m_Data) << endl;//0000003C3011F92Ccout << &(c.Animal::m_Data) << endl;//0000003C3011F928 不会覆盖
}int main() {Test();return 0;
}
5.5 同名函数访问
#include <iostream>
using namespace std;class Animal {
public:Animal() {}void eat() {cout << "动物吃东西" << endl;}
};class Cat : public Animal {
public:Cat() {}void eat() {// Animal::eat();//第一种cout << "猫吃东西" << endl;}
};int main() {Cat c;c.eat();//子类覆盖父类//c.Animal::eat();//第二种return 0;
}
5.6 多继承
#include <iostream>
using namespace std;class BaseA {
public:int m_A;int m_Base;BaseA() : m_A(0), m_Base(520) {}//初始化
};class BaseB {
public:int m_B;int m_Base;BaseB() : m_B(0), m_Base(1314) {}
};class BaseC {
public:int m_C;BaseC() : m_C(0) {}
};class Son : public BaseA, public BaseB, public BaseC {};int main() {Son s;s.m_A = 1;s.m_B = 2;s.m_C = 3;//s.m_Base = 8;//错误:不明确s.BaseA::m_Base = 8;s.BaseB::m_Base = 9;cout << &s.BaseA::m_Base << endl;//存在不同地址cout << &s.BaseB::m_Base << endl;cout << sizeof(s) << endl;//20 5个整型return 0;
}
6、多态
6.1 多态的语法
#include <iostream>
using namespace std;/*
静态多态:函数重载,运算符重载
动态多态:派生类和虚函数实现运行时的多态
*/class Animal {
public:// 虚函数virtual void eat() {cout << "动物在吃东西" << endl;}
};class Cat : public Animal {
public:void eat() {cout << "猫在吃东西" << endl;}
};class Pig : public Animal {
public:void eat() {cout << "猪在吃东西" << endl;}
};// main -> test -> eat -> Animal::eat
// 函数传参是个动物,但是传入不同的动物,会产生不同的行为,这就叫多态
void eat(Animal& a) {a.eat();
}void Test() {Cat c;Pig p;eat(c);//不加virtual,调用Animal的eat()eat(p);//加了 eat()猪在吃东西
}int main() {Test();return 0;
}
6.2 虚函数
#include <iostream>
using namespace std;class Animal {
public:virtual void eat() {cout << "动物在吃东西" << endl;}virtual void run() {cout << "动物在跑" << endl;}
};class Cat : public Animal {
public:void eat() {cout << "猫在吃东西" << endl;}
};void eat(Animal& a) {Animal b;a.eat();
}void Test() {Cat c;eat(c);cout << "Animal's size = " << sizeof(Animal) << endl;//不加virtual =1 加了=8->指针大小
}int main() {Test();return 0;
}
6.3 纯虚函数和抽象类
#include <iostream>using namespace std;class Animal { //有纯虚函数 是抽象类 无法实例化
public:virtual void eat() = 0;//纯虚函数,在子类实现
};class Cat : public Animal {
public:virtual void eat() {cout << "猫在吃东西" << endl;}
};int main() {Cat c;c.eat();return 0;
}
6.4 虚析构和纯虚析构
#include <iostream>
using namespace std;class BaseA {
public:BaseA() {}~BaseA() {cout << "BaseA 销毁了" << endl;}
};class SonA : public BaseA {
public:SonA() : m_Value(NULL) {m_Value = new int(10);//初始化 为10}~SonA() {cout << "SonA 销毁了" << endl;delete m_Value;}int* m_Value;
};class BaseB {
public:BaseB() {}/*virtual ~BaseB() {cout << "BaseB 销毁了" << endl;}*/virtual ~BaseB() = 0;//纯虚析构
};BaseB::~BaseB() {cout << "BaseB 销毁了" << endl;
}class SonB : public BaseB {
public:SonB() : m_Value(NULL) {m_Value = new int(10);}~SonB() {cout << "SonB 销毁了" << endl;delete m_Value;}int* m_Value;
};int main() {BaseA* a = new SonA();delete a;BaseB* b = new SonB();delete b;// BaseB x; 抽象类无法进行实例化return 0;
}
相关文章:
03 面向对象
1、封装 1.1 属性和行为 #include <iostream> using namespace std;// 面向对象三大特性:封装、继承、多态/* 封装的语法:class 类名 { 访问权限:属性(成员变量)行为(成员函数) }; */class Hero {/…...
【YOLOv12改进trick】多尺度大核注意力机制MLKA模块引入YOLOv12,实现多尺度目标检测涨点,含创新点Python代码,方便发论文
🍋改进模块🍋:多尺度大核注意力机制(MLKA) 🍋解决问题🍋:MLKA模块结合多尺度、门控机制和空间注意力,显著增强卷积网络的模型表示能力。 🍋改进优势…...
java 初学知识点总结
自己总结着玩 1.基本框架 public class HelloWorld{ public static void main(String[] args){ }//类名用大写字母开头 } 2.输入: (1)Scanner:可读取各种类型,字符串相当于cin>>; Scanner anew Scanner(System.in); Scan…...
File文件和目录
一、文件和目录相关概念 计算机文件(File):以计算机硬盘为载体存储在计算机上的信息集合,可以是文本(.txt)、图片(.jpg、.png、.jpeg)、视频(.mp4)、程序(.exe)等,文件一般有拓展名,表示文件的类型。 文件…...
C++ 数据结构详解及学习规划
C++数据结构详解及学习规划 一、C++常用数据结构详解与示例 以下是C++中核心数据结构的分类及具体实现示例: 1. 线性数据结构 a. 数组(Array) • 定义:存储固定大小、同类型元素的连续内存结构。 • 特点:快速随机访问(O(1)),但插入/删除效率低(O(n))。 • 应用场…...
Mac同时安装jdk8和jdk17,默认选择jdk8
在Mac上同时安装JDK 8和JDK 17,并设置默认版本为JDK 8,可以按照以下步骤操作: 一、下载并安装JDK 8和JDK 17 下载JDK 8 访问Oracle JDK下载页面。在“Java SE Archive Downloads”部分,找到JDK 8的下载链接。选择适合您Mac芯片类…...
PTA 7-6 列出连通集
题目详情: 给定一个有 n 个顶点和 m 条边的无向图,请用深度优先遍历(DFS)和广度优先遍历(BFS)分别列出其所有的连通集。假设顶点从 0 到 n−1 编号。进行搜索时,假设我们总是从编号最小的顶点出…...
计算机毕业设计SpringBoot+Vue.js疗养院管理系统(源码+文档+PPT+讲解)
温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 作者简介:Java领…...
分布式系统设计(架构能力)
一、微服务架构 服务治理 Nacos 注册中心(AP模式) CAP选择:Nacos 默认采用 AP 模式(可用性 分区容忍性),通过心跳检测实现服务健康管理。服务发现:客户端定时拉取服务列表,支持权重…...
CR电路介绍
CR电路(RC电路)介绍 CR电路(电阻-电容电路)由电阻(R)和电容(C)组成,是电子系统中的基础模块,广泛用于信号处理、定时、滤波等场景。以下是其核心功能、实现方…...
Redis数据结构,渐进式遍历,数据库管理
1.Redis的其他数据结构 前面我们主要讲述了Redis中比较常用的集中数据结构String,List,Hash,Set,Zset,但这并不代表Redis只用这几种数据结构还有如Streams,Geospatial,Hyperloglog,…...
动态规划01背包问题系列一>最后一块石头的重量II
这里写目录标题 题目分析:状态表示:状态转移方程:初始化:填表顺序:返回值:代码呈现:优化版本:代码呈现: 题目分析: 状态表示: 状态转移方程&#…...
GCC编译
目录 gcc编译c语言流程: 步骤 编译器 预处理 编译 汇编 链接 完整编译 多文件编译 其他常用gcc选项 gcc编译c语言流程: 预处理大写-E 编译为大写-S ,生成汇编代码文件 汇编为小写-c 链接这里可以加-o 重命名a.out这个可…...
康谋分享 | 3DGS:革新自动驾驶仿真场景重建的关键技术
随着自动驾驶技术的迅猛发展,构建高保真、动态的仿真场景成为了行业的迫切需求。传统的三维重建方法在处理复杂场景时常常面临效率和精度的挑战。在此背景下,3D高斯点阵渲染(3DGS)技术应运而生,成为自动驾驶仿真场景重…...
Jetson NV 上解决 PyQt5 “Could not load the Qt platform plugin ‘xcb‘“ 错误
在 Jetson NV 上运行 PyQt5 应用程序时,可能会遇到以下错误: qt.qpa.xcb: could not connect to display qt.qpa.plugin: Could not load the Qt platform plugin "xcb" in "" even though it was found. This application failed…...
计算机毕业设计Python+DeepSeek-R1大模型微博的话题博文及用户画像分析系统 微博舆情可视化(源码+ 文档+PPT+讲解)
温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 作者简介:Java领…...
文件上传靶场(1--9关)
实验环境: 1,upload的靶场环境可以去GitHub上自行查找 2,打开小皮面板的nginx和数据库 3,将文件上传的靶场部署到本地: 放到小皮的phpstduy_pro的www下面 小提示: 另外如果你用的是php7的版本建议将版…...
2025年渗透测试面试题总结-字某某动-安全研究实习生(二面)(题目+回答)
网络安全领域各种资源,学习文档,以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具,欢迎关注。 目录 字某某动-安全研究实习生(二面) 1. 护网行动中的核心工作 2. 防护层级选择&…...
LeetCode 965题详解 | 单值二叉树的“一统江湖”:如何判断所有节点值全等?
题目如下: 解题过程如下: 示例中,即便这个结点是空结点也返回true。 若根结点不为空,那么先判断它的左孩子结点里的值是否与根结点里的值相等(这里要先确保左孩子不为空,因为左孩子结点里的值是解引用操作…...
Java阻塞队列深度解析:高并发场景下的安全卫士
一、阻塞队列的核心价值 在电商秒杀系统中,瞬时涌入的10万请求如果直接冲击数据库,必然导致系统崩溃。阻塞队列如同一个智能缓冲带,通过流量削峰和异步解耦两大核心能力,成为高并发系统的核心组件。 二、Java阻塞队列实现类对比 …...
使用 Docker 部署 RabbitMQ 并实现数据持久化
非常好!以下是一份完整的 Docker 部署 RabbitMQ 的博客文档,包含从安装到问题排查的详细步骤。你可以直接将其发布到博客中。 使用 Docker 部署 RabbitMQ 并实现数据持久化 RabbitMQ 是一个开源的消息队列系统,广泛应用于分布式系统中。使用…...
VsCode 快捷键备忘
移动光标及选择文本 Ctrl ← / → :以单词为单位移动游标Home / End:光标移到行首/行位Ctrl Home / End:光标移到文件首和文件尾Ctrl Shift \:在匹配的分隔符之间跳转 配对的分隔符 是指分隔代码元素的字符,比如字…...
蓝桥杯备考:动态规划路径类DP之矩阵的最小路径和
如题,要求左上角到右下角的最短路径,我们还是老样子按顺序做 step1:确定状态表示 f[i][j]表示(1,1)到(i,j)的最短距离 step2 :推导状态表达方程 step3:确定填表顺序,应该是从上到下,从左到右 step4:初始化 step5 找结果&#…...
大模型工程师学习日记(十五):Hugging Face 模型微调训练(基于 BERT 的中文评价情感分析)
1. datasets 库核心方法 1.1. 列出数据集 使用 d atasets 库,你可以轻松列出所有 Hugging Face 平台上的数据集: from datasets import list_datasets# 列出所有数据集 all_datasets list_datasets()print(all_datasets)1.2. 加载数据集 你可以通过 l…...
Spring Boot 异步编程
文章目录 一、异步方法的使用1. 开启异步支持2. 定义异步方法3. 调用异步方法踩坑记录心得体会 二、线程池配置1. 自定义线程池2. 使用自定义线程池踩坑记录心得体会 三、异步任务的监控与管理1. 日志记录2. 异常处理3. 线程池监控踩坑记录心得体会 在现代应用程序开发中&#…...
golang并发编程如何学习
《掌握 Golang 并发编程的通关秘籍》 在当今的编程世界中,Golang 并发编程正以其独特的魅力和强大的能力吸引着众多开发者。然而,对于许多小伙伴来说,如何学好这门技术却成了一个头疼的问题。别担心,今天就让我来为大家揭开 Gola…...
Django 中,Form 和 ModelForm的用法和区别
在 Django 中,Form 和 ModelForm 是用于处理表单数据的两种主要方式。它们的主要区别在于是否与模型(Model)直接关联。以下是它们的用法、区别以及高级用法的详细说明: 一、Form 的使用 1. 基本用法 Form 是一个独立的表单类,不与任何模型直接关联。适用于需要手动定义字…...
SQL_语法
1 数据库 1.1 新增 create database [if not exists] 数据库名; 1.2 删除 drop database [if exists] 数据库名; 1.3 查询 (1) 查看所有数据库 show databases; (2) 查看当前数据库下的所有表 show tables; 2 数据表 2.1 新增 (1) 创建表 create table [if not exists…...
Linux网络编程
网络:不同主机,进程间通信 目的 1, 解决主机之间的硬件层面的互联互通 2,解决主机间软件层面的互联互通 IP地址:区分不同主机(软件地址) MAC地址:硬件地址 端口号:区分同…...
算法·搜索
搜索问题 搜索问题本质也是暴力枚举,一般想到暴力也要想到利用回溯枚举。 排序和组合问题 回溯法 去重问题:定义全局变量visited还是局部变量visited实现去重? 回溯问题 图论中的搜索问题 与一般的搜索问题一致,只不过要多…...
前端跨域设置 withCredentials: true
在做登录认证的时候,会出现请求未登录的情况,查看请求头的时候发现并没有把登录时的cookie设置到第二次的请求头里面。查看资料才知道跨域请求要想带上cookie,必须要在ajax请求里加上 withCredentials: true 再次访问发现请求头可以携带cook…...
使用 Arduino 和 Wi-Fi 控制 RGB LED
通过 WiFi 的 Arduino RGb LED 控制器 ,在本文中,我们将介绍下一个基于 IOT 的项目 - 使用 Wi-Fi 的 RGB LED 闪光灯。在这里,我们使用 Arduino 和 ESP8266 Wi-Fi 模块通过 Android 手机通过 Wi-Fi 控制 RGB LED 的颜色。 在这个 RGB Flash…...
html+js 轮播图
<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>轮播图示例</title><style>/* 基本样式…...
蓝桥杯 Excel地址
Excel地址 题目描述 Excel 单元格的地址表示很有趣,它使用字母来表示列号。 比如, A 表示第 1 列, B 表示第 2 列, Z 表示第 26 列, AA 表示第 27 列, AB 表示第 28 列, BA 表示第 53 列&#x…...
相机几何与标定:从三维世界到二维图像的映射
本系列课程将带领读者开启一场独特的三维视觉工程之旅。我们不再止步于教科书式的公式推导,而是聚焦于如何将抽象的数学原理转化为可落地的工程实践。通过解剖相机的光学特性、构建成像数学模型、解析坐标系转换链条,直至亲手实现参数标定代码࿰…...
SCI期刊推荐 | 免版面费 | 计算机领域:信息系统、软件工程、自动化和控制
在学术研究领域,选择合适的SCI期刊对科研成果的传播与认可至关重要。了解SCI期刊的研究领域和方向是基础,确保投稿内容与期刊主题相符。同时,要关注期刊的影响因子和评估标准,选择具有较高影响力和学术认可度的期刊。阅读期刊的投…...
Cryptography 与 PyCryptodome 源码级解析
目录 Cryptography 与 PyCryptodome 源码级解析一、引言二、Cryptography 库源码解析2.1 Cryptography 库概述与设计理念2.2 核心模块与数据流分析2.2.1 目录结构与模块划分2.2.2 以 AES-GCM 模式为例的加解密实现2.2.3 源码示例解析 2.3 错误处理与边界检测 三、PyCryptodome …...
std::string的模拟实现
目录 string的构造函数 无参数的构造函数 根据字符串初始化 用n个ch字符初始化 用一个字符串的前n个初始化 拷贝构造 用另一个string对象的pos位置向后len的长度初始化 [ ]解引用重载 迭代器的实现 非const版本 const版本 扩容reserve和resize reserve resize p…...
GPU、NPU与LPU:大语言模型(LLM)硬件加速器全面对比分析
引言:大语言模型计算基础设施的演进 随着大语言模型(LLM)的快速发展与广泛应用,高性能计算硬件已成为支撑LLM训练与推理的关键基础设施。目前市场上主要有三类处理器用于加速LLM相关任务:GPU(图形处理单元…...
常见限流算法
限流是指在高并发、大流量请求的情况下,限制新的流量对系统的访问,以保证系统服务的安全性。常见的限流算法及其详细介绍如下: 计数器算法(Fixed Window Counter) 原理:使用一个固定时间窗口内的计数器来…...
美国国家航空航天局(NASA)的PUNCH任务
地球浸没在来自太阳的物质流中。这种被称为太阳风的流正在冲刷我们的星球,造成令人叹为观止的极光,影响太空中的卫星和宇航员,甚至影响地面基础设施。 美国宇航局 (NASA) 的 PUNCH(统一日冕和日球层旋光仪 Polarimeter to Unify the Corona and Heliosphere)任务将首次…...
REST API前端请求和后端接收
1、get请求,带"?" http://localhost:8080/api/aop/getResult?param123 GetMapping("getResult")public ResponseEntity<String> getResult(RequestParam("param") String param){return new ResponseEntity<>("12…...
OpenBMC:BmcWeb构造connect对象
OpenBMC:BmcWeb server.run-CSDN博客 server在接收了tcp连接请求后,会构造一个ConnectionType对象,然后通过post调度,运行该对象的start函数 1.ConnectionType类型 其实也就是using ConnectionType = Connection<Adaptor, Handler>;类型 由于ConnectionType实例化于…...
ESLint 深度解析:原理、规则与插件开发实践
在前端开发的复杂生态中,保障代码质量与规范性是构建稳健、可维护项目的基石。ESLint 作为一款强大的代码检查工具,其默认规则与插件能满足多数常见需求,但面对特定团队规范或项目独特要求,自定义 ESLint 插件便成为有力的扩展手段…...
ios使用swift调用deepseek或SiliconFlow接口
调用SiliconFlow API 注册并获取API密钥:打开硅基流动平台官网Models,进行注册和认证。登录后,进入首页,点击左上角三个横杠,选择API密钥,生成密钥并复制。配置第三方应用:打开安装好的Chatbox…...
贪心算法一
> 作者:დ旧言~ > 座右铭:松树千年终是朽,槿花一日自为荣。 > 目标:了解什么是贪心算法,并且掌握贪心算法。 > 毒鸡汤:有些事情,总是不明白,所以我不会坚持。早安! >…...
Java进阶:Dubbo
分布式RPC框架Apache Dubbo 1. 软件架构的演进过程 软件架构的发展经历了由单体架构、垂直架构、SOA架构到微服务架构的演进过程,下面我们分别了解一下这几个架构。 1.1 单体架构 架构说明: 全部功能集中在一个项目内(All in one…...
【Day9】make/makeFile如何让项目构建自动化起飞
【Day9】make/makeFile如何让项目构建自动化起飞 使用make命令编写makefile文件依赖管理增量构建makefile注释:#makefile其他语法 make/makefile递归式工作过程 在Linux中,项目自动化构建是指使用一系列工具和脚本来自动执行软件项目的编译、测试、打包和…...
SCI1区TOP:自适应学习粒子群算法SLPSO,深度解析+性能实测
目录 1.摘要2.改进策略3.自适应学习粒子群算法4.结果展示5.参考文献6.获取代码 1.摘要 粒子群算法(PSO)是一种基于种群的随机搜索方法,广泛应用于科学和工程领域的连续空间优化问题,并已证明其高效性和有效性。许多实际问题的往往…...
迷你世界脚本显示板管理接口:DisPlayBoard
显示板管理接口:DisPlayBoard 迷你世界 更新时间: 2023-04-26 10:21:14 具体函数名及描述如下: 序号 函数名 函数描述 1 showBoard(...) 对玩家显示显示板 2 hideBoard(...) 对玩家隐藏显示板 3 setBoardPicture 对玩家设置显示板的图片…...