面向对象 学习黑马视频(03)
1.内存分区模型
/* 面向对象编程** 内存分区模型* 1.代码区:存放函数体的二进制代码,由操作系统进行管理的* 2.全局区:存放全局变量和静态变量以及常量* 3.栈区:由编译器自动分配释放,存放函数的参数值,局部变量等* 4.堆区:由程序员分配和释放,若程序员不释放,程序结束时由操作系统回收** 1.1程序运行前:* 在程序编译后,生成了exe可执行程序,未执行该程序前分为两个区域* 代码区:* 1.存放cpu执行的机器指令* 2.代码区是共享的,共享的目的是对于频繁被执行的程序,只需要在内存中存在一份即可* 3.代码区是只读的,使其只读的原因是防止程序以外地修改了他的指令* 全局区:* 1.全局变量和静态变量存放在此* 2.全局区还包含了常量区,字符串常量区和其他常量也存放在此* 3.该区域的数据在程序结束后由操作系统释放。** 1.2程序运行后* 栈区:* 1.由编译器自动分配释放,存放函数的参数值,局部变量等* 注意事项:不要返回局部变量的地址,栈区开辟的数据由编译器自动释放** 堆区:* 1.由程序员分配释放,若程序员不释放,程序结束时由操作系统回收* 在C++中主要利用new在堆区开辟内存*/
//创建全局变量;全局变量在函数外面
int g_a=10;
//const修饰的全局变量
const int c_g_a=10;
int main() {//静态变量static int s_a=10;//常量//字符串常量 "" 引起来的都是字符串常量//const//const修饰的局部变量 在堆区const int a=10;//堆区int * pint=new int(10);cout<<"pint="<<*pint<<endl;return 0;
}
2.new;delete;引用
/** new 语法** 堆区的数据 由程序员管理释放,* 如果想释放堆区的数据,利用关键字 delete** 引用* 作用:给变量起别名* 语法:数据类型 &别名 = 原名;* 注意:* 1.引用必须初始化* 2.引用在初始化后,不可以改变** 引用做函数参数* 作用:函数传参时,可以利用引用的技术让形参修饰实参* 优点:可以简化指针修改实参** 引用做函数返回值* 作用:引用是可以作为函数的返回值存在的* 注意:不要返回局部变量引用* 用法:函数调用作为左值 test04()=1000;** 引用的本质* 本质:引用的本质在C++内部实现是一个指针常量** 常量引用* 作用:常量引用主要用来修饰形参,防止误操作* 在函数参数列表中,可以加const修饰形参,防止形参改变实参*/
int * func(){//在堆区创建整型数据//new返回是: 该类型数据的指针int *p=new int(10);return p;
}
void test01(){int *p=func();cout<<*p<<endl;delete p;
// cout<<*p<<endl; //内存已被释放,再次访问,是非法操作
}
//2.在堆区医用new开辟数组
void test02(){//创建10整型数据的数组,在堆区int *arr=new int[10];//10代表数组有十个元素for(int i=0;i<10;i++){arr[i]=i+100;}for(int i=0;i<10;i++){cout<<arr[i]<<endl;}//释放堆区数组//释放数组的时候,要加[]delete[] arr;
}//交换函数
//值交换
void mysqap01(int a,int b){int temp=a;a=b;b=temp;
}
//地址交换
void mysqap02(int *a,int *b){int temp=*a;*a=*b;*b=temp;
}
//引用交换
void mysqap03(int &a,int &b){int temp=a;a=b;b=temp;
}//引用做函数的返回值
//1.不要返回局部变量的引用
int& test03(){int a=10;//局部变量 存放在栈区,函数结束,释放return a;
}
//2.函数的调用可以作为左值
int& test04(){static int a=110; //静态变量 全局区;程序结束,系统释放return a;
}
int main() {//1.new的基本语法test01();//2.在堆区利用new开辟数组test02();cout<<endl;cout<<"引用"<<endl;int a=10;int &b=a;b=20;cout<<"a="<<a<<endl;cout<<"b="<<b<<endl;
// int &c; //错误,没有初始化//引用一旦初始化了,就不可以更改了int c=15;b=c; //赋值操作,而不是更改引用给b赋值了
// &b=c; 报错cout<<endl;cout<<"引用在函数中的应用"<<endl;int aa=10;int bb=20;mysqap01(aa,bb);cout<<"值交换"<<"aa="<<aa<<";bb="<<bb<<";"<<endl;mysqap02(&aa,&bb);cout<<"地址交换"<<"aa="<<aa<<";bb="<<bb<<";"<<endl;mysqap03(aa,bb);cout<<"引用交换"<<"aa="<<aa<<";bb="<<bb<<";"<<endl;cout<<endl;cout<<"引用做函数返回值"<<endl;int &ref=test03();cout<<"&ref="<<&ref<<endl;cout<<"&ref="<<&ref<<endl;int &staticRef=test04();cout<<"&staticRef="<<staticRef<<endl;cout<<endl;cout<<"常量引用"<<endl;const int & reef=10;
// reef=20; //加入const之后,变为只读,不能修改return 0;
}
3.函数提高
/*** 函数提高** 函数默认参数* 在C++中,函数的形参列表中的形参是可以有默认值的。* 语法:返回值类型 函数名 (参数=默认值){}* 注意:* 1.默认参数,必须从右往左,不能跳过参数* 2.若果函数声明有默认参数,函数实现就不能有默认参数** 函数占位参数* C++中函数的形参列表里可以有占位参数,用来做占位,调用函数时必须填补该位置* 语法:返回值类型 函数名 (数据类型){}** 函数重载* 作用:函数名可以相同,提高复用性* 函数重载满足条件:* 1.同一个作用域下* 2.函数名称相同* 3.函数参数类型不同 或者 个数不同 或者 顺序不同* 注意:函数的返回值不可以作为函数重载的条件* 函数重载的注意事项* 1.引用作为重载的条件* 2.函数重载碰到默认参数* @return*///1.默认形参
void text01(int a=10){cout<<"默认值a="<<a<<endl;
}
//2.函数占位参数 ;后面课程会用到
//占位参数还可以有默认值
void text02(int a,int){//如何使用 第二个参数 疑问?
}
void text03(int a,int=20){}//重载
void text04(int a,double b){}
void text04(double b,int a){}
void text04(int a,int b,int c){}
void text04(double a,double b){}
int main() {text01();text01(15);text02(10,12);return 0;
}
4.类和对象
/** 类和对象** 三大特性:封装、继承、多态 【与java一个样】*///设计一个圆类,求圆的周长
//圆求周长的公式:2*PI*半径
//class 代表设计一个类,类后面紧跟着的就是类名称
const double PIQ=3.1415;
#define PIAA 3.1415
class Circle{//访问权限
public://属性int m_r;//行为double calculateZC(){return 2*PIQ*m_r;}double calculateZC2(){return 2*PIAA*m_r;}
};
int main() {Circle c1;c1.m_r=5;cout<<"圆的周长为:"<<c1.calculateZC()<<endl;cout<<"圆的周长为:"<<c1.calculateZC2()<<endl;return 0;
}
5.封装;struct与class的区别
/** 封装* 类在设计时,可以把属性和行为放在不同权限下,加以控制** 访问权限 与java一样* 1.public 公公权限* 成员在类内可以访问;类外可以访问* 2.protected 保护权限* 类内可以访问;类外不能访问 ;子类可以访问父类的保护内容* 3.private 私有权限* 成员类内可以访问;类外不可以访问;子类不能访问父类的内容** struct和class区别* 唯一区别:默认访问权限不同* 1.struct默认权限为共有* 2.class默认权限为私有** 成员属性设置为私有* 1.可以自己控制读写权限* 2.对于写可以检测数据的有效性*/
struct C2{int m_A; //默认是公共权限
};
class Person{int m_A; //默认权限 私有
public://公共权限string m_Name;protected://保护权限string m_Car;private://私有权限int m_Password;
public:void func(){m_Name="张三";m_Car="丰田";m_Password=981201;}
};
//成员属性设置为私有 与java 一样
// 1.可以自己控制读写权限
// 2.对于写可以检测数据的有效性
class Person22{string m_Name;int m_Age;string m_Lover; //情人
public://设置姓名void setName(string name){m_Name=name;}string getName(){return m_Name;}
};
int main() {//实例化具体对象cout<<"权限学习"<<endl;Person p1;p1.m_Name="李四";//p1.m_Car="拖拉机";//访问不到//p1.m_Password=123; //不可以访问cout<<endl;cout<<"成员属性设置为私有"<<endl;Person22 p2;p2.setName("张三");cout<<"p2.m_Name="<<p2.getName()<<endl;return 0;
}
6.案例 长方体求面积和体积,两个是否相同
/** 案例** 设计立方体类* 求出立方体的面积和体积* 分别用全局函数和局部函数判断两个立方体是否相等*/
class Cube{//长宽高 默认属性(private)int along;int awidth;int ahigh;public://长宽高 set get 函数//若要精细,可以添加上对输入的判断是否复合要求void setAlong(int chang){along=chang;}int getAlong(){return along;}void setAwidth(int kuan){awidth=kuan;}int getAwidth(){return awidth;}void setHigh(int gao){ahigh=gao;}int getAHigh(){return ahigh;}//计算面积函数int area(){return along*ahigh*2+along*awidth*2+ahigh*awidth*2;}//计算体积int volume(){return along*awidth*ahigh;}//判断两个立方体是否相等bool equal(Cube cube){//第一种:可以自己写长宽高对比 简单//第二种:校验是否真实的相等 玛法}
};
int main() {Cube c1;c1.setAlong(2);c1.setAwidth(3);c1.setHigh(4);cout<<"面积为:"<<c1.area()<<endl;cout<<"体积为:"<<c1.volume()<<endl;return 0;
}
7.对象的初始化和清理
构造函数 析构函数(1)
/*** 对象的初始化和清理** 生活中我们买的电子产品都基本会有出厂设置,在某一天我们不用时候也会删除一些自己信息数据保证安全* C++中的面向对象来源于生活,每个对象也都会有初始设置以及对象销毁前的清理数据的设置。** 构造函数和析构函数* 对象的初始化和清理是两个非常重要的安全问题* 1.一个对象或者变量没有初始状态,对其使用后果未知* 2.使用完一个对象或者变量,没有及时清理,也会造成安全问题* 构造函数和析构函数会被编译器自动调用,完成对象初始化和清理工作* 对象的初始化和清理工作是编译器强制要我们做的事情,因此如果我们不提供析构和构造,编译器是会提供析构函数和构造函数的空实现** 构造函数:主要作用在于创建对象时为对象的成员属性赋值,构造函数由编译器自动调用,无需手动调用。* 语法 类名(){}* 1.构造函数,没有返回值也不写 void* 2.函数名称与类名相同* 3.构造函数可以有参数,因此可以发生重载* 4.程序在调用对象时候会自动调用构造,无需手动调用,而且只会调用一次* 析构函数:主要作用于对象销毁前系统自动调用,执行一些清理工作。* 语法 ~类名(){}* 1.析构函数,没有返回值也不写 void* 2.函数名称与类名相同,在类名前加上 ~* 3.析构函数不可以有参数,因此不可以发生重载* 4.程序在对象销毁前自动调用,无需手动调用,而且只会调用一次** 构造函数分类及调用* 参数分类:有参构造和无参构造* 类型分类:普通构造和拷贝构造* 调用方式:* 括号法* 显示法* 隐式转换法** @return*///构造函数和析构函数
class Person{
public://1.1构造函数Person(){cout<<"构造函数"<<endl;}//析构函数~Person(){cout<<"析构函数"<<endl;}
};//构造函数分类及调用
class Person22{
public:int age;Person22(){cout<<"无参构造函数"<<endl;}Person22(int a){age=a;cout<<"有参构造函数"<<endl;}//拷贝构造函数 const 限制防止修改Person22(const Person22 &p){age=p.age;cout<<"拷贝构造函数"<<endl;}~Person22(){cout<<"析构函数"<<endl;}
};
//调用
void text01(){//1.括号法Person22 p22; //默认构造Person22 p23(10); //有参构造Person22 p24(p22); //拷贝构造函数cout<<"p22地址为:"<<&p22<<endl;cout<<"p24地址为:"<<&p24<<endl;//2.显示法Person22 p222; //默认构造Person22 p223=Person22(10); //有参构造Person22 p224=Person22(p22); //拷贝构造函数Person22(10); //匿名对象 特点:当前执行结束后,系统会立即回收掉匿名对象//3.隐式转换法Person22 p4=10; //相当于 Person22 p4=Person(10);Person22 p5=p4;
};//拷贝构造函数调用时机
class Person2{Person2(){}};
int main() {Person p;cout<<endl;cout<<"构造函数分类及调用"<<endl;text01();cout<<endl;return 0;
}
构造函数 析构函数(2)
/** 拷贝构造函数调用时机** C++中拷贝构造函数调用时机通常有三种情况* 1.使用一个已经创建完毕的对象来初始化一个新对象* 2.值传递的方式给函数参数传值* 3.以值方式返回局部对象** 构造函数调用规则* 默认情况下,c++编译器至少给一个类添加三个函数* 1.默认构造函数(无参,函数体为空)* 2.默认析构函数(无参,函数体为空)* 3.默认拷贝构造函数,对属性进行值拷贝** 构造函数调用规则:* 1.用户定义了有参构造函数,c++默认不再提供无参构造函数,但是会提供默认拷贝构造函数* 2.定义了拷贝构造函数,c++不再提供其他构造函数*/class Person {
public:int m_Age;Person() {cout << "Person默认构造函数" << endl;}Person(int age) {cout << "Person有参构造函数" << endl;m_Age = age;}Person(const Person &p) {cout << "Person拷贝构造函数" << endl;m_Age = p.m_Age;}
};// 1.使用一个已经创建完毕的对象来初始化一个新对象
void test01() {Person p1(20);Person p2(p1);
}// 2.值传递的方式给函数参数传值
void doWork(Person p) {cout << "p=" << p.m_Age << endl;
}void test02() {Person p;doWork(p);
}// 3.以值方式返回局部对象
Person doWork2() {Person p1;return p1;
}void test03() {Person p = doWork2();
}int main() {cout << "拷贝构造函数调用时机" << endl;
// test01();
// test02();test03();return 0;
}
8.深拷贝 浅拷贝
/** 深拷贝 浅拷贝* 浅拷贝:简单的赋值拷贝操作【编译器提供的默认拷贝构造函数,为浅拷贝函数】* 深拷贝:在堆区重新申请空间,进行拷贝操作*/
class Person{
public:int age;int *height;Person(){cout<<"Person默认构造函数"<<endl;}Person(int agea,int heighta){cout<<"Person有参构造函数"<<endl;age=agea;height=new int(heighta);
// height=heighta;}//自定义深拷贝构造函数Person(Person &p){cout<<"Person 深拷贝 构造函数"<<endl;age=p.age;
// height=p.height; //浅拷贝,编译器默认执行的代码height=new int(*p.height);}~Person(){cout<<"Person的析构函数"<<endl;//析构代码 , 将堆区开辟数据做释放操作if(height!=NULL){delete height;height=NULL;}}
};
void test01(){Person p1(18,160);cout<<"p1的年龄为:"<<p1.age<<"height="<<*p1.height<<"p1.height的地址为"<<p1.height<<endl;Person p2(p1);cout<<"p2的年龄为:"<<p2.age<<"height="<<*p2.height<<"p2.height的地址为"<<p2.height<<endl;
}
int main() {test01();return 0;
}
9.初始化列表
/** 初始化列表* 作用:C++提供了初始化列表语法,用来初始化属性* 语法:构造函数():属性1(值1),属性2(值2)...{}*/
class Person{
public:string name;int age;Person(string _name,int _age){name=_name;age=_age;}Person():name("张三"),age(18){cout<<"我被初始化了"<<endl;}
};
void test01(){Person person;cout<<"person.name="<<person.name<<";person.age="<<person.age<<endl;
}
int main() {test01();return 0;
}
10.类对象作为类成员
包含:构造函数顺序和析构函数顺序
/** 类对象作为类成员* 类中的成员可以是另一个类的对象,我们称为 对象成员** 当其他类对象作为本类成员,构造时候先构造类对象,再构造自身,* 析构函数,先释放自己类对象,再释放其他类对象*/
class Phone{
public:string pName;Phone(string name){cout<<"我是Phone构造函数"<<endl;pName=name;}~Phone(){cout<<"我是Phone析构函数"<<endl;}
};
class Person{
public :string name;Phone phone;//Phone phone=pName 隐式转换法 ,直接调用 Phone中的构造方法赋值Person(string name,string pName):name(name),phone(pName){cout<<"我是Person构造函数"<<endl;}~Person(){cout<<"我是Person析构函数"<<endl;}
};
void test01(){Person p("张三","苹果max");cout<<"p.name="<<p.name<<";p.phone="<<p.phone.pName<<endl;
}
int main() {test01();return 0;
}
/** 打印输出结果为:* 我是Phone构造函数* 我是Person构造函数* p.name=张三;p.phone=苹果max* 我是Person析构函数* 我是Phone析构函数*/
11.静态成员变量;静态成员函数
成员变量
/** 静态成员** 静态成员就是在成员变量和成员函数前加上关键字static,称为静态成员* 静态成员分为:* 1.静态成员变量:* 所有对象共享同一份数据* 在编译阶段分配内存* 类内声明,类外初始化* 2.静态成员函数* 所有对象共享同一个函数* 静态成员函数只能访问静态成员变量** 静态变量不属于某一个对象,* 访问方式* 1.通过对象进行访问* 2.通过类名进行访问** 静态成员变量也有访问权限*/
class Person {
public:static int a; //静态成员;不能直接赋值; 类内声明
};int Person::a = 10; //类外初始化void test01() {Person p;
// p.a;cout << "p.a=" << p.a << endl;
}//访问方式
void test02() {//1.通过对象进行访问Person p;cout << p.a << endl;//2.通过类名进行访问cout << Person::a << endl;
}int main() {
// test01();test02();return 0;
}
成员函数
/** 静态成员函数** 静态成员函数也有访问权限,和普通函数访问权限一样*/
class Person {
public:static int a;int b;//静态成员函数static void func() {a = 200; //静态成员函数可以访问 静态成员变量
// b=20; //静态成员函数 不可以访问 非静态成员变量cout << "static void fun 被调用" << endl;}
};int Person::a = 100;//访问方式
void test01() {//1.通过对象访问Person p;p.func();//2.通过类名访问Person::func();
}int main() {test01();return 0;
}
/** 输出结果:* static void fun 被调用* static void fun 被调用*/
12.C++对象模型 ;this
C++对象模型
/** C++对象模型** 成员变量和成员函数分开存储** 在C++中,类中的成员变量和成员函数分开存储* 只有非静态成员变量才属于类的对象上*/
class Person {
public://非静态成员变量占用对象空间int a;//静态成员变量不占用对象空间static int b;Person() {a = 0;}//函数也不占对象空间,所有函数共享一个函数实例void func() {cout << "a=" << &a <<";b="<<&b<< endl;}
};
int Person::b=12;
void text01() {Person p;p.func();Person p1;p1.func();
}int main() {text01();cout<<endl;cout<<"this指针"<<endl;return 0;
}
this指针
/** this指针* this指针指向被调用的成员函数所属的对象* this指针是隐含每一个非静态成员函数内的一种指针* this指针不需要定义,直接使用即可** this指针用途* 1.当形参和成员变量同名时,可用this指针来区分* 2.在类的非静态成员函数中返回对象本身,可以使用 return *this*/
class Person {
public:int age;Person(int age) {//this指针指向被调用的成员函数 所属的对象this->age = age;}Person &PersonAddAge(Person &p) {this->age += p.age;return *this;}
};void test() {Person p(15);cout << "p.age=" << p.age << endl;
}void test02() {Person p1(10);Person p2(10);p2.PersonAddAge(p1).PersonAddAge(p1).PersonAddAge(p1); //链式编程cout << "p2的年龄为:" << p2.age << endl;
}int main() {
// test();test02();return 0;
}
/** 运行结果:* p2的年龄为:40*/
空指针访问成员函数
/** 空指针访问成员函数** C++中空指针也是可以调用成员函数的,但是也要注意有没有用到this指针** 如果用到this指针,需要加以判断保证代码的健壮性*/
class Person{
public:void showClassName(){cout<<"this is a Person"<<endl;}void showPersonAge(){//报错原因:传入的指针是NULLif(this==NULL){ //提高代码健壮性return;}cout<<"age="<<age<<endl; ///cout<<"age="<<this.age<<endl; 属性默认前面有this}int age;
};
void test01(){Person * p =NULL;p->showClassName();p->showPersonAge();
}
int main() {test01();return 0;
}
const 修饰成员函数 ;常对象
/** const 修饰成员函数* 常函数:* 1.成员函数后加 const后我们称这个函数为 常函数* 2.常函数内不可以修改成员属性* 3.成员属性声明时加关键字 mutable 后,在常函数中依然可以修改* 常对象:* 1.声明对象前加 const 称该对象为常对象* 2.常对象只能调用常函数**/
class Person {
public:string m_A;mutable string m_b; //成员属性声明时加关键字 mutable 后,在常函数中依然可以修改//this指针的本质 是指针常量 指针的指向是不可以修改的//Person * const this;//在成员函数后面加 const,修饰的是this指向,让指针指向的值也不可以修改void showPerson() const {
// this->m_A=100; //报错;不可以修改
// this=NULL; //错误;this指针不可以修改指针的指向this->m_b = "qwe"; //变量加入 mutable 关键字,可以修改了}void func() {}
};//常对象
void test02() {const Person p; //在对象前加 const,变为常对象
// p.m_A="aaa"; //报错,该值不可以修改p.m_b = "bbb"; //m_b是特殊值(mutable关键字 修饰),在常对象下也可以修改//常对象只能调用常函数p.showPerson();
// p.func(); //错误;常对象不能调用普通函数
}int main() {test02();return 0;
}
13.友元
友元,让其他类可以访问本类中的私有变量
(1)全局函数做友元
/** 友元** 在程序里,有些私有属性也想让类外特殊的一些函数或者类进行访问,就需要用到友元的技术** 友元的目的就是让一个函数或者类访问另一个类中私有成员** 关键字:friend** 友元的三种实现:* 1.全局函数做友元* 2.类做友元* 3.成员函数做友元*/
class Building {//goodGay全局函数是 Building 好朋友,可以访问 Building中的私有成员//该行代码作用是给 goodGay 全局函数开权限friend void goodGay(Building *building);public:Building() {m_sittingRoom = "客厅";m_BedRom = "卧室";}string m_sittingRoom; //客厅
private:string m_BedRom;
};//全局函数
void goodGay(Building *building) {cout << "好基友的全局函数 正在访问 sittingRoom" << building->m_sittingRoom << endl;cout << "好基友的全局函数 正在访问 BedRoom" << building->m_BedRom << endl;}void test01() {Building building;goodGay(&building);
}int main() {test01();return 0;
}
(2)友元类
/** 类做友元*/
class Building;class GoodGay {
public:GoodGay(); //声明构造函数Building *building;void visit(); //参观函数,访问Building中的属性
};class Building {//GoodGay 是 Building 的好基友类(友元类),所以GoodGay中的对象可以访问Building中的私有成员friend class GoodGay;public:Building();string m_sittingRoom; //客厅
private:string m_BedRoom; //卧室
};Building::Building() {m_sittingRoom = "客厅";m_BedRoom = "卧室";
}GoodGay::GoodGay() {//创建一个建筑物对象building = new Building;
}void GoodGay::visit() {cout << "好基友类正在访问" << building->m_sittingRoom << endl;cout << "好基友类正在访问" << building->m_BedRoom << endl;
}void test01() {GoodGay gg;gg.visit();
}int main() {test01();return 0;
}
(3)成员函数 友元
/** 成员函数做友元*/
class Building;class GoodGay {
public:GoodGay();void visit(); //让visit可以访问Building中私有成员void visit2(); //让visit2不可以访问Building中私有成员Building *building;
};class Building {//告诉编译器 GoodGay类下的visit成员函数作为本类的好朋友,可以访问本类的私有成员friend void GoodGay::visit();public:string m_sittingRoom; //卧室Building();private:string m_BedRoom; //客厅
};Building::Building() {m_sittingRoom = "客厅";m_BedRoom = "卧室";
}GoodGay::GoodGay() {building = new Building();
}void GoodGay::visit() {cout << "visit函数正在访问:" << building->m_sittingRoom << endl;cout << "visit函数正在访问:" << building->m_BedRoom << endl;
}void GoodGay::visit2() {cout << "visit函数正在访问:" << building->m_sittingRoom << endl;
// cout << "visit函数正在访问:" << building->m_BedRoom << endl; //报错;visit2()函数没有friend 好朋友权限
}void test01() {GoodGay goodGay;goodGay.visit();
}int main() {test01();return 0;
}
14.运算符重载
加号预算符重载
/** 运算符重载概念:* 对已有的运算符进行重新定义,赋予其另一种功能,以适应不同的数据类型。**加号运算符重载* 作用:实现两个自定义数据类型相加的运算*/class Person {
public:int m_A;int m_B;//成员函数重载+号Person operator+(Person &p) {Person temp;temp.m_A = this->m_A + p.m_A;temp.m_B = this->m_B + p.m_B;return temp;}
};//全局函数重载+号
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;
}void test01() {Person p1;p1.m_A = 10;p1.m_B = 5;Person p2;p2.m_A = 10;p2.m_B = 5;Person p3 = p1.operator+(p2);cout << "p3.m_A=" << p3.m_A << endl;cout << "p3.m_B=" << p3.m_B << endl;}int main() {test01();//全局函数cout << "全局函数调用重载+号函数" << endl;Person p1;p1.m_A = 10;p1.m_B = 5;Person p2;p2.m_A = 10;p2.m_B = 5;//p4=p1+02;//本质Person p4 = operator+(p1, p2);return 0;
}
左移运算符重载
/** 左移运算符重载*/
class Person {
public:int a;int b;//重载左移运算符
// void operator<<(){
//
// }
};//全局函数重载左移运算符
//如果要输出私有成员,可以将该函数添加为友元函数
ostream &operator<<(ostream &cout, Person &p) { //本质 operator<<(cout,p) 简化 cout << pcout << "p.a=" << p.a << ";p.b=" << p.b << endl;return cout;
}void test01() {Person p;p.a = 10;p.b = 20;cout << "p= " << p << endl;
}int main() {test01();return 0;
}
/** 输出结果:* p= p.a=10;p.b=20*/
递增运算符重载
/** 递增运算符重载*/class MyInteger {friend ostream &operator<<(ostream &out, MyInteger &myint);public:MyInteger() {num = 17;}//重载前置++运算符 返回引用是为了一直对一个数据进行递增操作MyInteger & operator++() {num++;return *this;}//重载后置++运算符//int 代表的一个占位参数,可以用于区分,前置和后置递增MyInteger & operator++(int) {++num;return *this;}private:int num;
};//重载左移运算符
ostream &operator<<(ostream &out, MyInteger &myint) {return out << "MyInteger object=" << myint.num << endl;
}void test01() {MyInteger myint;cout << "前置递增:" << ++myint << endl;cout << "后置递增:" << myint++ << endl;cout << "后置递增:" << myint << endl;
}int main() {test01();return 0;
}
赋值运算符重载
/** 赋值运算符重载** C++编译器至少给一个类添加4个函数* 1.默认构造函数(无参,函数体为空)* 2.默认析构函数(无参,函数体为空)* 3.默认拷贝构造函数* 4.赋值运算符operator=,对属性进行值拷贝*/
class Person {
public:int *m_Age;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;}
};void test01() {Person p1(19);cout << "p1的年龄为:" << *p1.m_Age << endl;cout << "" << endl;Person p2(20);p2 = p1; //赋值操作*p1.m_Age = 23;cout << "p2的年龄为:" << *p2.m_Age << endl;Person p3(30);p3 = p2 = p1; //链式操作cout << "p1的年龄为:" << *p1.m_Age << endl;cout << "p2的年龄为:" << *p2.m_Age << endl;cout << "p3的年龄为:" << *p3.m_Age << endl;
};int main() {test01();return 0;
}
关系运算符重载 == !=
/** 关系运算符重载** 作用:重载关系运算符,可以让两个自定义类型对象进行对比操作**/
class Person{
public:string m_Name;int m_Age;Person(string name,int age){m_Name=name;m_Age=age;}//operator 重载==bool operator==(Person &p){if(this->m_Name!=p.m_Name){return false;}if(this->m_Age!=p.m_Age){return false;}return true;}//operator 重载!=bool operator!=(Person &p){if(this->m_Name!=p.m_Name){return true;}if(this->m_Age!=p.m_Age){return true;}return false;}
};void test01(){Person p1("tom",18);Person p2("tom",18);if(p1==p2){cout<<"p1==p2"<<endl;}
}
int main() {test01();return 0;
}
函数调用运算符重载
/** 函数调用运算符重载** 函数调用运算符() 也可以重载* 由于重载后使用的方式非常像函数的调用,因此称为仿函数* 仿函数没有固定写法,非常灵活**/class MyPrint {
public://重载函数调用运算符void operator()(string test) {cout << test << endl;}
};void test01() {MyPrint myPrint;myPrint("打印这条语句"); //使用起来非常像一个函数,所以叫仿函数
}int main() {test01();return 0;
}
15.继承
(1)继承介绍
/** 继承* 继承是面向对象三大特性之一** 语法:class 子类 : 继承方式 父类{}* 子类 也称为 派生类* 父类 也称为 父类** 继承的是共性,书写的是个性*/Java页面
//class Java{
//public:
// void header(){
// cout<<"首页、公开课、登录、注册。。。(公共头部)"<<endl;
// }
// void footer(){
// cout<<"帮助中心、交流合作、站内地图。。。(公共底部)"<<endl;
// }
// void left(){
// cout<<"java python c++ (公共分类列表)"<<endl;
// }
// void content(){
// cout<<"Java学科视频"<<endl;
// }
//};
//
Java页面
//class Python{
//public:
// void header(){
// cout<<"首页、公开课、登录、注册。。。(公共头部)"<<endl;
// }
// void footer(){
// cout<<"帮助中心、交流合作、站内地图。。。(公共底部)"<<endl;
// }
// void left(){
// cout<<"java python c++ (公共分类列表)"<<endl;
// }
// void content(){
// cout<<"Python学科视频"<<endl;
// }
//};//继承页面实现
//公共页面类
class BasePage {
public:void header() {cout << "首页、公开课、登录、注册。。。(公共头部)" << endl;}void footer() {cout << "帮助中心、交流合作、站内地图。。。(公共底部)" << endl;}void left() {cout << "java python c++ (公共分类列表)" << endl;}
};class Java : public BasePage {
public:void content() {cout << "java学科视频" << endl;}
};class Python : public BasePage {
public:void content() {cout << "Python学科视频" << endl;}
};void test01() {cout << "java学科页面如下" << endl;Java java;java.header();java.content();java.footer();cout << endl;cout << "python学科页面如下" << endl;Python python;python.header();python.content();python.footer();cout << endl;
}int main() {test01();return 0;
}
(2)继承方式
/*** 继承方式* 1.公共继承* 2.保护继承* 3.私有继承** @return*///公共继承
class Base1 {
public:int a;
protected:int b;
private:int c;
};class Son1 : public Base1 {
public:void func() {a = 10; //父类中公共权限,到子类中依然是公共权限b = 10;//父类中保护权限,到子类中依然是保护权限//c=10; //访问不到}
};//保护继承
class Base2 {
public:int a;
protected:int b;
private:int c;
};class Son2 : protected Base2 {
public:void func() {a = 10; //父类中公共权限,到子类中变为 保护权限b = 10;//父类中保护权限,到子类中依然是保护权限
// c=10; //访问不到}
};//私有继承
class Base3 {
public:int a;
protected:int b;
private:int c;
};class Son3 : private Base3 {
public:void func() {a = 100; //公共权限到子类变为 私有成员b = 100;//保护权限到子类变为 私有成员
// c=100; //父类中的成员,防蚊不到}
};void test01() {Son1 s1;s1.a = 100;//s1.b=100; //保护权限,类外访问不到
}void test02() {Son2 s2;//s2.a=0; //变为了保护权限,因此访问不到//s2.b=0; //保护权限,因此访问不到//s2.c=0;//私有权限,访问不了
}void test03() {Son3 s;//s.a=0; //都是私有成员,访问不到//s.b=0; //都是私有成员,访问不到//s.c=0; //都是私有成员,访问不到
}int main() {return 0;
}
(3) 继承中的对象模型
/** 继承中的对象模型** 问题:从父类继承过来的成员,哪些属于子类对象中**/class Base {
public:int a;
protected:int b;
private:int c;
};class Son : public Base {
public:int d;
};void test01() {//父类中所有非静态成员属性都会被子类继承下去//父类中私有成员属性 是被编译器给隐藏了,因此是访问不到。但是确实被继承下去了cout << "size of Son=" << sizeof(Son) << endl;
}int main() {test01();return 0;
}
/**打印结果:size of Son=16*/
(4)继承中构造和析构顺序
/** 继承中构造和析构顺序** 子类继承父类后,当创建子类对象,也会调用父类的构造函数** 问题:父类和子类的构造和析构顺序是谁先谁后?*/
class Base {
public:Base() {cout << "Base()构造函数" << endl;}~Base() {cout << "Base()~析构函数" << endl;}
};class Son : public Base {
public:Son() {cout << "Son()构造函数" << endl;}~Son() {cout << "Son()~析构函数" << endl;}
};void test01() {Son son;
}int main() {test01();return 0;
}
/** 运行结果:* Base()构造函数* Son()构造函数* Son()~析构函数* Base()~析构函数*/
(5)继承同名成员处理方式
/** 继承同名成员处理方式** 问题:当子类与父类出现同名的成员,如何通过子类对象,访问到子类或者父类中同名的数据呢?** 访问子类同名成员,直接访问即可* 访问父类同名成员 需要加作用域**/class Base {
public:int a;Base() {a = 100;}void func() {cout << "Base::func()函数" << endl;}void func(int a) {cout << "Base::func(int a)函数" << endl;}
};class Son : public Base {
public:int a;Son() {a = 200;}void func() {cout << "Son::func()函数" << endl;}
};void test01() {Son son;cout << "a=" << son.a << endl;//若果通过子类对象,访问父类中同名成员,需要加作用域cout << "a=" << son.Base::a << endl;son.func();son.Base::func();//如果子类中出现和父类同名的成员函数,子类的同名成员会隐藏掉父类中所有同名成员函数//如果想访问到父类中被隐藏的同名函数,需要加作用域son.Base::func(100);
}int main() {test01();return 0;
}
//返回结果
//a=200
//a=100
//Son::func()函数
//Base::func()函数
//Son::func(int a)函数
(6)继承同名静态成员处理方式
/** 继承同名静态成员处理方式** 静态成员和非静态成员出现同名,处理方式一样** 访问子类同名成员 直接访问即可* 访问父类同名成员 需要加作用域**/class Base {
public:static int a;
};class Son : public Base {
public:static int a;
};int Base::a = 10;
int Son::a = 100;void test01() {//1.通过对象来访问Son son;cout << "son.a=" << son.a << endl;cout << "son.Base::a=" << son.Base::a << endl;//2.通过类名来访问cout << "通过类名来访问:" << endl;cout << "Son.a=" << Son::a << endl;cout << "通过Son访问Base.a=" << Son::Base::a << endl;cout << "直接访问Base.a=" << Base::a << endl;
}int main() {test01();return 0;
}
/** son.a=100* son.Base::a=10* 通过类名来访问:* Son.a=100* 通过Son访问Base.a=10* 直接访问Base.a=10*/
(7)多继承语法
/** 多继承语法** C++运行一个类继承多个类** 语法:class 子类 : 继承方式 父类1 , 继承方式 父类.....** 多继承可能会引发父类中有同名成员出现,需要加作用域区分** 注意:C++实际开发中不建议多继承**/class Base1{
public:int a;Base1(){a=10;}
};class Base2{
public:int a;Base2(){a=10;}
};class Son:public Base1,public Base2{
public:int c;int d;Son(){c=12;d=13;}
};void test(){Son s;cout<<"sizeof(s)="<<sizeof (s)<<endl;//当父类中出现同名成员,需要加作用域区分cout<<"s.Base1::a="<<s.Base1::a<<endl;cout<<"s.Base2::a="<<s.Base2::a<<endl;
}int main() {test();return 0;
}
/** sizeof(s)=16* s.Base1::a=10* s.Base2::a=10*/
(8)菱形继承
/** 菱形继承** 概念:* 两个派生类继承同一个基类* 又有某一类同时继承两个派生类* 这种继承被称为菱形继承或者砖石继承** 总结:* 菱形继承带来的主要问题是子类继承两份相同的数据,导致资源浪费以及毫无意义* 利用虚继承可以解决菱形继承问题**/
//动物类
class Animal {
public:int age;
};//利用虚继承,可以解决菱形继承的问题
//继承之前 加上关键字 virtual 变为虚继承
//Animal类称为 虚基类
//虚继承 之后,相同名称的变量,会共享内存
//羊类
class Sheep : virtual public Animal {
};//驼类
class Tuo : virtual public Animal {};class SheepTuo : public Sheep, public Tuo {};void test01() {SheepTuo sheepTuo;sheepTuo.Sheep::age = 18;sheepTuo.Tuo::age = 28;cout << "sheepTuo.Sheep::age=" << sheepTuo.Sheep::age << endl;cout << "sheepTuo.Tuo::age=" << sheepTuo.Tuo::age << endl;cout << "sheepTuo.age=" << sheepTuo.age << endl;
}int main() {test01();return 0;
}
/** sheepTuo.Sheep::age=28* sheepTuo.Tuo::age=28* sheepTuo.age=28*/
16.多态
(1)多态基础
/*** 多态** 基本概念* 多态分为两类:* 静态多态:函数重载 和 运算符重载属于静态多态,复用函数名* 动态多态:派生类和虚函数实现运行时多态* 静态多态和动态多态区别* 静态多态的函数地址早绑定 - 编译阶段确定函数地址* 动态多态的函数地址晚绑定 - 运行阶段确定函数地址*** 地址早绑定 在编译阶段就确定了地址* 如果想执行让猫说话,那么这个函数地址就不能提前绑定,需要在运行阶段进行绑定,地址晚绑定* 动态多态满足条件* 1.有继承关系* 2.子类重写父类虚函数 ;重写:函数返回值类型 函数名 参数列表 完全相同** 动态多态的使用* 父类的指针或者引用,指向子类对象**/class Animal {
public://虚函数virtual void speak() {cout << "动物在说话" << endl;}
};class Cat : public Animal {
public:void speak() {cout << "小猫在说话" << endl;}
};//执行说话的函数
//地址早绑定 在编译阶段就确定了地址
//如果想执行让猫说话,那么这个函数地址就不能提前绑定,需要在运行阶段进行绑定,地址晚绑定//动态多态满足条件
//1.有继承关系
//2.子类重写父类虚函数 ;重写:函数返回值类型 函数名 参数列表 完全相同
//
//动态多态的使用
//父类的指针或者引用,指向子类对象
void doSpeak(Animal &animal) {animal.speak();
}void test01() {Cat cat;doSpeak(cat);
}int main() {test01();return 0;
}
(2)纯虚函数和抽象类
/** 纯虚函数和抽象类** 在多态中,通常父类中虚函数的实现是毫无意义的,主要都是调用子类重写的内容* 因此可以将虚函数更改为 纯虚函数** 纯虚函数语法:virtual 返回值类型 函数名 (参数列表)=0;* 当类中有了纯虚函数,这个类也称为抽象类** 抽象类特点:* 无法实例化对象* 子类必须重写抽象类中的纯虚函数,否则也属于抽象类*/class Base {
public://纯虚函数//只要有一个纯虚函数,这个类称为抽象类virtual void func() = 0;
};class Son : public Base {void func() {cout << "func函数调用" << endl;}
};void test01() {//Base b; //抽象类无法实例化对象//new Base; //抽象类无法实例化对象Son s; //子类必须重写父类的纯虚函数,否则不能实例化对象Base *base = new Son;base->func();
}int main() {test01();return 0;
}
(3)析构和纯虚析构
/** 虚析构和纯虚析构* 多态使用时,如果子类中有属性开辟到堆区,那么父类指针在释放时无法调用到子类的析构代码* 解决方式:将父类中的析构函数改为虚析构或者纯虚析构** 虚析构和纯虚析构共性:* 可以解决父类指针释放子类对象* 都需要具体的函数实现* 虚析构和纯虚析构区别:* 如果是纯虚析构,该类属于抽象类,无法实例化对象** 虚析构语法:* virtual ~类名(){}* 纯虚析构语法:* vertual ~类名()=0;* 类名::~类名(){}**/class Animal {
public://纯虚函数virtual void speak() = 0;//利用虚析构可以解决,父类指针释放子类对象时不干净问题//虚析构
// virtual ~Animal(){
// cout<<"Animal析构函数调用"<<endl;
// }//纯虚虚构//需要声明,也需要实现//有了纯虚析构之后,这个类也属于抽象类virtual ~Animal() = 0;
};//Animal纯虚析构的实现类
Animal::~Animal() {cout << "Animal纯虚析构函数调用" << endl;
}class Cat : public Animal {
public:string *name;Cat(string aname) {name = new string(aname);}virtual void speak() {cout << *name << "小猫在说话" << endl;}~Cat() {if (name != NULL) {cout << "cat析构函数调用" << endl;delete name;name = NULL;}}
};void test01() {Animal *animal = new Cat("Tom");animal->speak();delete animal;
}int main() {test01();return 0;
}/** Tom小猫在说话* cat析构函数调用* Animal纯虚析构函数调用*/
相关文章:
面向对象 学习黑马视频(03)
1.内存分区模型 /* 面向对象编程** 内存分区模型* 1.代码区:存放函数体的二进制代码,由操作系统进行管理的* 2.全局区:存放全局变量和静态变量以及常量* 3.栈区:由编译器自动分配释放,存放函数的参数值…...
FinClip 支持创建 H5应用类小程序;PC 终端 优化升级
FinClip 的使命是使您能够通过小程序解决关键业务流程挑战,并完成数字化转型。不妨让我们看看本月产品与市场发布亮点,是否有助于您实现目标。 产品方面的相关动向👇👇👇 FinClip 支持创建 H5应用类小程序 近期我们…...
YOLOV8实例分割——详细记录环境配置、自定义数据处理到模型训练与部署
前言 Ultralytics YOLOv8是一种前沿的、最先进的(SOTA)模型,它在前代YOLO版本的成功基础上进行了进一步的创新,引入了全新的特性和改进,以进一步提升性能和灵活性。作为一个高速、精准且易于操作的设计,YO…...
2309ddocx02文档
风格,页眉和页脚等内容与主要分开,允许在起始文档中放大量自定义,然后在生成文档中显示. 打开文档 from docx import Document document Document() document.save("test.docx")真正打开文档 要用文件名打开文档: document Document("existing-document-f…...
第一章初识微服务
文章目录 认识微服务单体架构分布式架构需要考虑的问题 微服务微服务的具体架构微服务技术对比企业中的技术需求 总结 服务拆分注意事项 认识微服务 随着互联网行业的发展,对服务的要求也越来越高,服务架构也从单体架构逐渐演变为现在流行的微服务架构。…...
微信小程序电影票订票小程序软件设计与实现
摘 要 我们的生活水平正在不断的提高,然而提高的一个重要的侧面表现就是更加注重我们的娱乐生活。电影是我们都喜欢的一种娱乐方式,各式各样的电影给我们带来的喜悦也是大不相同的。带来快乐的同时也因为其复杂、繁琐的流程让电影爱好者们变得烦躁起来。…...
Redis 缓存预热+缓存雪崩+缓存击穿+缓存穿透
面试题: 缓存预热、雪萌、穿透、击穿分别是什么?你遇到过那几个情况?缓存预热你是怎么做的?如何造免或者减少缓存雪崩?穿透和击穿有什么区别?他两是一个意思还是载然不同?穿适和击穿你有什么解…...
java 面试题汇总整理
java有哪四种引用类型 在Java中,有四种引用类型,用于控制对象的生命周期和垃圾回收行为。这些引用类型包括: 强引用(Strong Reference): 强引用是最常见的引用类型,它们是默认的引用类型。当一…...
淘宝开放平台免审核接入 获取淘宝卖家订单列表订单详情API
taobao.open.trades.sold.get 搜索当前会话用户作为卖家已卖出的交易数据(只能获取到三个月以内的交易信息) 1. 返回的数据结果是以订单的创建时间倒序排列的。 注意:type字段的说明,如果该字段不传,接口默认只查4种类…...
Mybatis中的关系映射
1.一对一的映射关系 一对一关系(One-to-One)表示两个实体对象之间存在唯一的关联关系。例如,一个学生只能拥有一个身份证。在 MyBatis 中,我们可以使用结果嵌套或一对一映射来处理一对一关系。 1.1 创建模型类和Vo类 package com…...
领域建模之数据模型设计方法论
本文通过实际业务需求场景建模案例,为读者提供一种业务模型向数据模型设计的方法论,用于指导实际开发中如何进行业务模型向数据模型转化抽象,并对设计的数据模型可用性、扩展性提供了建议性思考。通过文章,读者可以收获到业务模型…...
springboot毕业生信息招聘平台设计与实现
摘 要 随着社会的发展,社会的各行各业都在利用信息化时代的优势。计算机的优势和普及使得各种信息系统的开发成为必需。 毕业生信息招聘平台,主要的模块包括查看管理员;首页、个人中心、企业管理、空中宣讲会管理、招聘岗位管理、毕业生管理…...
开发前期准备工作
开发前期准备工作 文章目录 开发前期准备工作0 代码规范0.1 强制0.2 推荐0.3 参考dao:跟数据库打交道service:业务层,人类思维解决controller:抽象化 0.4 注释规范0.5 日志规范0.6 专有名词0.7 控制层统一异常统一结构体控制层提示…...
k8s deployment服务回滚,设置节点为不可调度
服务回滚 通过滚动升级的策略可以平滑的升级Deployment,若升级出现问题,需要最快且最好的方式回退到上一次能够提供正常工作的版本。为此K8S提供了回滚机制。 revision:更新应用时,K8S都会记录当前的版本号,即为revi…...
信息系统安全运维和管理指南
声明 本文是学习 信息系统安全运维管理指南. 而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 安全运维支撑系统 信息系统安全服务台 目的 对信息系统安全事件进行统一监控与处理。 要求 建立一个集中的信息系统运行状态收集、处理、显示及报警的系…...
现货黄金代理好吗?
做黄金代理这个职业好吗?从目前的市场现状来看,其实做黄金代理很不错的。在股票市场中,投资者只能通过买涨进盈利,所以当市场行情不好的时候,股票经纪人的业务将很难展开,而现货黄金投资者不一样࿰…...
BCSP-玄子Share-Java框基础_双系统Redis安装与基础语法
四、Redis 4.1 Redis 简介 Redis 是开源、高性能的key-value数据库,属于 NoSQL 数据库 NoSQL 数据库与关系型数据库 关系型数据库:采用关系模型来组织数据,主要用于存储格式化的数据结构NoSQL 数据库:泛指非关系型数据库&…...
android system_server WatchDog简介
简介 android系统中SystemServer WatchDog的主要作用是监控SystemServer进程的运行状态,防止其卡住或者死锁。 具体来说,watchDog线程会定期去检查SystemServer线程的运行情况。如果发现SystemServer线程超过一定时间未有响应,watchDog会认为SystemServer进程发生了问题,这时…...
华为---OSPF协议优先级、开销(cost)、定时器简介及示例配置
OSPF协议优先级、开销、定时器简介及示例配置 路由协议优先级:由于路由器上可能同时运行多种动态路由协议,就存在各个路由协议之间路由信息共享和选择的问题。系统为每一种路由协议设置了不同的默认优先级,当在不同协议中发现同一条路由时&am…...
MEMORY-VQ: Compression for Tractable Internet-Scale Memory
本文是深度学习相关文章,针对《MEMORY-VQ: Compression for Tractable Internet-Scale Memory》的翻译。 MEMORY-VQ:可追溯互联网规模存储器的压缩 摘要1 引言2 背景3 MEMORY-VQ4 实验5 相关工作6 结论 摘要 检索增强是一种强大但昂贵的方法࿰…...
Docker 离线安装指南
参考文章 1、确认操作系统类型及内核版本 Docker依赖于Linux内核的一些特性,不同版本的Docker对内核版本有不同要求。例如,Docker 17.06及之后的版本通常需要Linux内核3.10及以上版本,Docker17.09及更高版本对应Linux内核4.9.x及更高版本。…...
Spark 之 入门讲解详细版(1)
1、简介 1.1 Spark简介 Spark是加州大学伯克利分校AMP实验室(Algorithms, Machines, and People Lab)开发通用内存并行计算框架。Spark在2013年6月进入Apache成为孵化项目,8个月后成为Apache顶级项目,速度之快足见过人之处&…...
Neo4j 集群管理:原理、技术与最佳实践深度解析
Neo4j 的集群技术是其企业级高可用性、可扩展性和容错能力的核心。通过深入分析官方文档,本文将系统阐述其集群管理的核心原理、关键技术、实用技巧和行业最佳实践。 Neo4j 的 Causal Clustering 架构提供了一个强大而灵活的基石,用于构建高可用、可扩展且一致的图数据库服务…...
基于matlab策略迭代和值迭代法的动态规划
经典的基于策略迭代和值迭代法的动态规划matlab代码,实现机器人的最优运输 Dynamic-Programming-master/Environment.pdf , 104724 Dynamic-Programming-master/README.md , 506 Dynamic-Programming-master/generalizedPolicyIteration.m , 1970 Dynamic-Programm…...
【Android】Android 开发 ADB 常用指令
查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...
Chromium 136 编译指南 Windows篇:depot_tools 配置与源码获取(二)
引言 工欲善其事,必先利其器。在完成了 Visual Studio 2022 和 Windows SDK 的安装后,我们即将接触到 Chromium 开发生态中最核心的工具——depot_tools。这个由 Google 精心打造的工具集,就像是连接开发者与 Chromium 庞大代码库的智能桥梁…...
Vue 模板语句的数据来源
🧩 Vue 模板语句的数据来源:全方位解析 Vue 模板(<template> 部分)中的表达式、指令绑定(如 v-bind, v-on)和插值({{ }})都在一个特定的作用域内求值。这个作用域由当前 组件…...
云安全与网络安全:核心区别与协同作用解析
在数字化转型的浪潮中,云安全与网络安全作为信息安全的两大支柱,常被混淆但本质不同。本文将从概念、责任分工、技术手段、威胁类型等维度深入解析两者的差异,并探讨它们的协同作用。 一、核心区别 定义与范围 网络安全:聚焦于保…...
Linux-进程间的通信
1、IPC: Inter Process Communication(进程间通信): 由于每个进程在操作系统中有独立的地址空间,它们不能像线程那样直接访问彼此的内存,所以必须通过某种方式进行通信。 常见的 IPC 方式包括&#…...
41道Django高频题整理(附答案背诵版)
解释一下 Django 和 Tornado 的关系? Django和Tornado都是Python的web框架,但它们的设计哲学和应用场景有所不同。 Django是一个高级的Python Web框架,鼓励快速开发和干净、实用的设计。它遵循MVC设计,并强调代码复用。Django有…...
