C++核心编程--对象篇
4.2、对象
4.2.1、对象的初始化和清理
用于对对象进行初始化设置,以及对象销毁前的清理数据的设置。
-
构造函数
和析构函数
- 防止对象初始化和清理也是非常重要的安全问题
- 一个对象或变量没有初始化状态,对其使用后果是未知的
- 同样使用完一个对象或变量,没有及时清理,也会造成一定的安全问题
- 在c++中会自动被编译器调用这俩个函数,完成对象的初始化和清理工作,
因此如果我们不手动提供构造和析构,编译器提供构造函数和析构函数是空实现
- 防止对象初始化和清理也是非常重要的安全问题
-
构造函数
- 主要作用在创建对象时为对象的成员属性赋值,构造函数由编译器自动调用,无需手动调用
- 写法:
类名(){}
- 构造函数,没有返回值也不写void
- 函数名称和类名相同
- 构造函数可以有参数,因此可以发生重载
- 程序在调用对象时候会自动调用构造,无需手动调用,而且只会调用一次
-
析构函数
- 主要作用在对象
销毁前
系统自动调用,执行一些清理 - 写法:
~类名(){}
- 析构函数,没有返回值也不写void
- 函数名称与类名相同,在名称前加上符号
- 析构函数不可以有参数,因此不可以发生重载
- 程序在对象前会自动调用析构,无需手动调用,而且只会调用一次
- 主要作用在对象
- 构造函数
#include<iostream>
using namespace std;//-构造函数,没有返回值也不写void
//- 函数名称和类名相同
//- 构造函数可以有参数,因此可以发生重载
//- 程序在调用对象时候会自动调用构造,无需手动调用,而且只会调用一次
class Person2 {
public:Person2() {cout << "person2的构造被调用" << endl;}~Person2() {cout << "person2的析构函数被调用" << endl;}
};void test05() {Person2 p1;
}int main() {test05();//栈上的数据执行完后会自动释放system("pause");return 0;
}
4.2.2、构造函数的分类和调用
- 分类方式
- 按参数分为:有参构造和无参构造
- 按类型分为:普通构造和拷贝构造
- 调用方式
- 括号法
- 显示法
- 隐式转换法
- 有参构造和无参构造
class Person2 {
public://无参有参构造Person2() {cout << "person2的构造被调用" << endl;}Person2(int a) {cout << "person2的构造被调用" << endl;}
};
- 普通构造和拷贝构造
//拷贝构造函数Person2(const Person2 &p) {//将传入的对象所有属性拷贝到身上age = p.age;}
- 括号法
//调用
void test06() {//-括号法Person2 p;//有参构造函数Person2 p1(10);Person2 p2(p1);cout << "P1的年龄:" << p1.age << endl;cout << "P2的年龄:" << p2.age << endl;//- 显示法//- 隐式转换法
}
调用默认构造函数的时候,不要加()
加括号会让编译器认为是一个函数的声明
- 显示法
//- 显示法
Person2 p1;
Person2 p2 = Person2(10);//有参构造
Person2 p3 = Person2(p2);//拷贝构造
匿名对象:直接调用不接收。
特点:当前行执行结束后,系统会立即回收
-
注意
不要利用拷贝构造函数 初始化匿名对象
//编译器会认为 Person(p3) === Person p3; 对象声明
Person2(p3);
-
隐式转换法
//- 隐式转换法 //相当于 写了 Person2 p4 = Person(10); Person2 p4 = 10; Person2 p5 = p4; //拷贝构造
4.2.3、拷贝构造函数调用时机
c++中拷贝构造函数通常有三种情况
- 使用一个已经创建完毕的对象来初始化一个新对象
- 值传递的方式给函数参数传值
- 以值方式返回局部对象
- 使用一个已经创建完毕的对象来初始化一个新对象
#include<iostream>
using namespace std;class Person3 {
public:Person3() {cout << "Person3构造函数被调用" << endl;}Person3(int a) {m_Age1 = a;cout << "Person3有参构造函数被调用" << endl;}Person3(const Person3 & p) {m_Age1 = p.m_Age1;cout << "Person3拷贝构造构造函数被调用" << endl;}~Person3() {cout << "Person3析构函数被调用" << endl;}int m_Age1;
};//-使用一个已经创建完毕的对象来初始化一个新对象
void test06() {Person3 p1(20);Person3 p2(p1);cout << "P2的年龄:"<<p2.m_Age1 << endl;
}int main() {test06();system("pause");return 0;
}
- 值传递的方式给函数参数传值
//- 值传递的方式给函数参数传值
//值传递会拷贝一个副本
void doWork(Person3 p) {}void test07() {Person3 p;doWork(p);
}//- 以值方式返回局部对象int main() {test07();system("pause");return 0;
}
- 以值方式返回局部对象
//- 以值方式返回局部对象Person3 doWork2() {//这里返回出去的是一个新的对象,会自己拷贝一个Person3 p1;cout << (int*)&p1 << endl;return p1;
}void test08() {//这里可以测试一下是不是同一个对象Person3 p = doWork2();cout << (int*)&p << endl;
}int main() {test08();system("pause");return 0;
}
4.2.4、构造函数调用规则
默认情况下,c++编译器至少给一个类添加3个函数
- 默认构造函数(无参,函数体为空)
- 默认析构函数(无参,函数体为空)
- 默认拷贝构造函数,对属性进行值拷贝
构造函数调用规则如下:
- 如果用户定义有参构造函数,c++不在提供默认无参构造,但是会提供默认拷贝构造
- 如果用户定义拷贝构造函数,c++不会再提供其他构造函数
- c++编译器至少给一个类添加3个函数
#include<iostream>
using namespace std;
//构造函数调用规则
class Person10 {
public:Person10() {cout << "person构造函数被调用" << endl;}Person10(int a) {m_age = a;cout << "person构造函数被调用" << endl;}Person10(const Person10 &p) {m_age = p.m_age;}~Person10() {cout << "person析构函数被调用" << endl;}int m_age;
};void test09() {Person10 p;p.m_age = 18;Person10 p2(p);cout << "p2的年龄为:" << p2.m_age << endl;}
int main() {test09();system("pause");return 0;
}
正常情况下输出结构
当我们随意注释掉一个函数,编译器依然可以自动运行,给我们提供一个临时的拷贝构造函数
- 如果用户定义有参构造函数,c++不在提供默认无参构造
这里我们注释掉自己写的无参构造,运行一下。
但是会提供默认拷贝构造
- 如果用户定义拷贝构造函数,c++不会再提供其他构造函数
我们将拷贝构造以外的所有函数注释掉
4.2.5、 深拷贝与浅拷贝
浅拷贝
:简单的赋值拷贝操作深拷贝
:在堆区重新申请空间,进行拷贝操作
浅拷贝带来的问题就是堆区内存重复释放
如果我们在函数中开辟了一段堆区数据,我们又用的浅拷贝方式,在运行析构函数时,两块空间都指向同一个地址释放,由于先进后出的原则
,前面的释放掉该地址,后面的再释放就会报错,所以需要用到深拷贝来解决该问题。
#include<iostream>
using namespace std;
class Person5 {
public:Person5() {cout << "Person5的构造函数被调用" << endl;}Person5(int a,int height) {m_age = a;//在堆区开辟个空间m_height = new int(height);cout << "Person5的参数构造函数被调用" << endl;}//析构函数的作用就是如果在函数中在堆区开辟了空间,需要手动释放~Person5() {if (m_height!=NULL){//释放掉空间delete m_height;//把值等于Null 防止野指针出现m_height = NULL;}cout << "Person5的析构函数被调用" << endl;}int m_age;int *m_height;
};void test06() {Person5 p1(18,160);cout << "P1的年龄为:" << p1.m_age <<"身高为:" <<*p1.m_height<< endl;Person5 p2(p1);cout << "P1的年龄为:" << p2.m_age << "身高为:" <<*p2.m_height << endl;
}int main() {test06();system("pause");return 0;
}
这里可以看到编译器因为重复释放问题报错,为了解决这个重复释放的问题,我们自己写一个拷贝构造函数,解决浅拷贝带来的问题
//自己实现拷贝构造函数 解决浅拷贝带来的问题Person5(const Person5 &p) {cout << "Person拷贝构造函数调用" << endl;m_age = p.m_age;//深拷贝操作m_height = new int(*p.m_height);}
这里重新开辟空间,大小为p.m_height的解引用
总结:如果属性有在堆区开辟的,一定要自己提供拷贝构造函数,防止浅拷贝带来的问题
4.2.6、初始化列表
作用:
C++提供了初始化列表语法,用来初始化属性
语法:
构造函数():属性1(值1),属性2(值2)…{}
#include<iostream>
using namespace std;
class Person7 {
public://传统赋值操作Person7(int a, int b, int c) {m_a = a;m_b = b;m_c = c;}//初始化列表初始化属性Person7(int a,int b,int c):m_a(a),m_b(b), m_c(c) {}int m_a;int m_b;int m_c;
};void test07() {Person7 p1(10,20,30);cout << "p1的a值为:"<< p1.m_a << endl;cout << "p1的b值为:"<< p1.m_b << endl;cout << "p1的c值为:"<< p1.m_c << endl;
}int main() {test07();system("pause");return 0;
}
4.2.7、类对象作为类成员
c++类中的成员可以是另一个类的对象,我们称为该成员为
成员对象
class A{}
class B{A a;
}
那么在创建B对象时,A,B的构造和解析的顺序是谁先谁后
#include<iostream>
#include<string>
using namespace std;class Phone {
public:Phone(string n):mP_Name(n) {cout << "Phone的构造函数调用" << endl;}string mP_Name;
};class Person0 {
public:Person0(string name, string pName) :m_Name(name), m_Phone(pName) {cout << "person的构造函数被调用" << endl;}string m_Name;Phone m_Phone;
};void test08() {Person0 p("zy", "华为");cout << "name:" << p.m_Name << "手机:" << p.m_Phone.mP_Name<< endl;
}
int main() {test08();system("pause");return 0;
}
构造时:我们可以看到是先有成员对象,再有的自身
析构时:先自身,再成员对象
也就是像栈的先进后出,后进先出
4.2.8、静态成员
静态成员就是在成员变量和成员函数前加上关键字
static
,称为静态成员
静态成员分为:
- 静态成员变量
- 所有对象共享同一份数据
- 再编译阶段分配内存
- 类内声明,类外初始化
- 静态成员函数
- 所有对象共享同一个函数
- 静态成员函数只能访问静态成员变量
- 静态成员变量
#include<iostream>
using namespace std;//静态成员变量
class Person {
public:static int m_A;
};
//- 所有对象共享同一份数据
//- 再编译阶段分配内存
//- 类内声明,类外初始化!!!必须要类外初始化int Person::m_A = 100;void test05() {Person p1;cout << "m_A的值为:" << p1.m_A << endl;Person p2;//所有对象共享同一份数据p2.m_A = 200;cout << "p2修改后m_A的值为:" << p1.m_A << endl;
}int main() {test05();system("pause");return 0;
}
静态成员变量 不属于某个对象上,所有对象都共享同一份数据。可通过对象进行访问,也可以直接通过类名进行访问
cout << "p2修改后m_A的值为:" << p1.m_A << endl;cout << "p2修改后m_A的值为:" << Person::m_A << endl;
如果写到private
权限下那么m_A的值在类外也不可以被访问
- 静态成员函数
静态函数和静态变量使用方法类似
#include<iostream>
using namespace std;class Person2 {
public:static void fun() {//静态成员函数只能访问静态成员变量m_A = 100;//m_B = 200;cout << m_A << endl;}static int m_A;int m_B;
};int Person2::m_A = 0;void test06() {Person2 p1;//两种访问方式p1.fun();Person2::fun();Person2 p2;//共用同一个方法p2.fun();
}
int main() {//test05();test06();system("pause");return 0;
}
静态成员函数只能访问静态成员变量
4.3、C++对象模型和this指针
4.3.1、成员变量和成员函数分开存储
在C++中,成员变量和成员函数分开存储
只有非静态成员变量才属于类的对象上
- 在C++中一个空对象占用的内存空间为1字节
#include<iostream>
using namespace std;//成员变量和成员函数分开存储
class Person {
};void test04() {Person p1;//C++会给每一个空对象分配一字节空间,//是为了区分空对象占用内存的位置cout << sizeof(p1) << endl;
}int main() {test04();system("pause");return 0;
}
- 如果里面声明了一个非静态变量,内存空间会发生改变
class Person {
public:int m_A;
};
void test05() {Person p2;cout << sizeof(p2) << endl;
}
- 静态成员变量、静态成员函数、非静态成员函数均不属于类对象上
class Person {
public:int m_A;static int m_B;void fun() {};static void fun2() {};
};
int Person::m_B = 0;void test05() {Person p2;cout << sizeof(p2) << endl;
}
4.3.2、this指针概念
通过4.3.1我们知道c++中成员变量和成员函数是分开存储的
每个非静态成员函数只会诞生一份函数实例,也就是多个同类型的对象会共用一块代码,那么这块代码是如何区分是那个对象调用了自己呢?
C++通过提供特殊的对象指针this指针
,解决上述问题。this指针指向被调用的成员函数所属的对象
this指针是隐含每一个非静态成员函数内的一种指针
this指针不需要定义,直接使用即可
this指针的用途:
- 当形参和成员变量同名时,可用this指针来区分
- 在类的非静态成员函数中返回对象本身,可使用return *this
this指针指向被调用的成员函数所属的对象
#include<iostream>
using namespace std;class Person6 {
public:Person6(int age) {age = age;}int age;
};void test06() {Person6 p1(10);cout << "P1的值为:" << p1.age << endl;
}int main() {test06();system("pause");return 0;
}
这里会出现编译器不认识age属于同一个
所以有两种方法,第一种改变名字,第二种用this指向
- 链式编程 *this返回自身
class Person6 {
public:Person6(int age) {this->age = age;}//做一个年龄+=操作//通过 *this返回自身,可以实现链式编程Person6& PersonAddAge(Person6 &p) {this->age += p.age;//this 指向的是p2的指针,而*this指向的就是对象本体return *this;}int age;
};
void test07() {Person6 p1(10);Person6 p2(10);p2.PersonAddAge(p1).PersonAddAge(p1).PersonAddAge(p1);cout << p2.age << endl;
}
如果不用解引用方式区返回,输出结果就为20
因为编译器会调用拷贝构造函数,创建一个新的对像,不会追加到自身上。
4.3.3、空指针访问成员函数
C++中空指针也是可以调用成员函数的,但是也要注意有没有用到this指针
如果用到this指针,需要加以判断保证代码的健壮性
#include<iostream>
using namespace std;class Person6 {
public:void showClassName() {cout << "this is Person class" << endl;}void showPersonAge() {//报错原因是因为传入的指针为Nullif (this == NULL){return;}cout << "age=" <<this-> m_Age << endl;}int m_Age;
};void test05() {Person6 *p = NULL;p->showClassName();p->showPersonAge();
}
int main() {system("pause");return 0;
}
4.3.4、const修饰成员函数
常函数:
- 成员函数后加const后我们称为这个函数为
常函数
- 常函数内不可以修改成员成员属性
- 成员属性声明时加关键字mutable后,在常函数中依然可以修改
常对象:
- 声明对象前加const称该对象为常对象
- 常对象只能调用常函数
class Person {
public://this指针的本质 是指针常量 指针的指向是不可以修改的// const Person * const this;//在成员函数后面加const,修饰的是this指向,让指针指向的值也不可以修改void showPerson() const {this->m_B = 100;//this = NULL; }void func() {m_A = 100;}int m_A;//特殊变量,即使在常函数中,也可以修改该值,加关键字mutablemutable int m_B; };void test05() {Person p1;p1.showPerson();
}void test06() {const Person p; //在对象前加const,变为常对象//p.m_A = 100;p.m_B = 100;//m_B是特殊值,在常对象也可以修改//常对象只能调用常函数p.showPerson();//p.func(); //常对象不可以调用普通成员函数,因为普通成员函数可以修改属性
}
4.4、友元
在程序里,有些私有属性也想让类外特殊的一些函数或者类进行访问,就需要用到友元的技术
友元的目的就是让一个函数或者类,访问另一个类中私有成员
关键字:friend
- 三种实现
- 全局函数做友元
- 类做友元
- 成员函数做友元
- 全局函数做友元
#include<iostream>
using namespace std;class Building {//为了让全局函数访问到私有的权限可以利用friend关键字friend void goodGay(Building* building);
public:Building() {m_sittingRoom = "客厅";m_BedRoom = "卧室";}public:string m_sittingRoom;
private:string m_BedRoom;
};
//全局函数
void goodGay(Building *building) {cout << "正在访问:" << building->m_sittingRoom << endl; cout << "正在访问:" << building->m_BedRoom << endl;
}void test05() {Building buiding;goodGay(&buiding);
}
int main() {test05();system("pause");return 0;
}
- 类做友元
#include<iostream>
#include<string>
using namespace std;class Building {//为了让类访问到私有的权限可以利用friend关键字friend class GoodGay;
public:Building();public:string m_sittingRoom;
private:string m_BedRoom;
};class Building;
class GoodGay {
public:GoodGay();//访问Building中的属性void visit();Building * building;};//类外写成员函数
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 test05() {GoodGay gg;gg.visit();
}
int main() {test05();system("pause");return 0;
}
- 成员函数做友元
#include<iostream>
#include<string>
using namespace std;class Building;
class GoodGay {
public:GoodGay();//让visit函数可以访问Building中的私有成员void visit();//让visit2函数不可以访问Building中的私有成员void visit2();
private:Building *building;
};class Building {friend void GoodGay::visit();
public:Building();
public: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 GoodGay::visit2() {cout << "函数正在访问:" << building->m_sittingRoom << endl;
};void test07() {GoodGay gg;gg.visit();
}
int main() {test07();system("pause");return 0;
}
4.5、运算符重载
概念:对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的类型数据
对于内置的数据类型的表达式的运算符是不能被修改的
例:1+1=0 是不被允许的
不能滥用运算符重载
例:原本为加法 写成 乘法
- 关键字:operator
4.5.1、加号运算符重载
- operator+
#include<iostream>
using namespace std;//加号运算符重载
class Person {
public://成员函数重载+号//Person operator+(Person& p1) {// Person temp;// temp.m_valueA = p1.m_valueA + this->m_valueA;// temp.m_valueB = p1.m_valueB + this->m_valueB;// return temp;//}
public:int m_valueA;int m_valueB;
};
//全局实现
Person operator+(Person &p1, Person& p2) {Person temp;temp.m_valueA = p1.m_valueA + p2.m_valueA;temp.m_valueB = p1.m_valueB + p2.m_valueB;return temp;
}
//重载实现
Person operator+(Person &p1, int num) {Person temp;temp.m_valueA = p1.m_valueA + num;temp.m_valueB = p1.m_valueB + num;return temp;
}
int main() {Person p1,p2,p3;p1.m_valueA = 10;p1.m_valueB = 20;p2.m_valueA = 10;p2.m_valueB = 20;p3 = p1 + p2;cout << p3.m_valueA << '\n' << p3.m_valueB << endl;//重载p4 = p1 +10;cout << p4.m_valueA << '\n' << p4.m_valueB << endl;system("pause");return 0;
}
4.5.2、左移运算符重载
- 关键字operator<<
#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 输出流类型
ostream& operator<<(ostream &cout,Person &p) {cout << "A:" << p.m_A << " B:" << p.m_B;return cout;
}void test07() {Person p1(10,10);cout << p1 << endl;;
}
int main() {test07();system("pause");return 0;
}
4.5.3、后置运算符重载
- operator++() 前置
- operator++(int) 后置
前置递增返回引用,后置递增返回值
#include<iostream>
using namespace std;
//重载递增class MyInterger {
friend ostream& operator<<(ostream& cout, MyInterger myint);
public:MyInterger() {m_Num = 0;}//重载前置++运算符MyInterger& operator++() {m_Num++;return *this;}//重载后置++运算符//int 代表占位可以用于区别前置和后置MyInterger operator++(int) {//先记录当时结果MyInterger temp = *this;//后递增m_Num++;//最后将记录的结果做返回return temp;}
private:int m_Num;
};
//重载<<运算符
ostream& operator<<(ostream& cout, MyInterger myint) {cout << myint.m_Num << endl;return cout;
}
void test06() {MyInterger myint;cout << ++myint << endl;
}int main() {test06();system("pause");return 0;
}
4.5.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) {//先判断是否有属性在堆区如果有先释放干净,然后再深拷贝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(18);Person p2(20);Person p3(40);p3 = p2 = p1;cout << *p1.m_Age << endl;cout << *p2.m_Age << endl;
}int main() {test01();system("pause");return 0;
}
4.5.5、关系运算符重载
- operator==
- operator!=
#include<iostream>
#include<string>
using namespace std;
class Person {
public: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 true;}return false;}//重载不等号bool operator!=(Person &p) {if (this->m_Name != p.m_Name && this->m_Age != p.m_Age){return false;}return true;}public:string m_Name;int m_Age;
};
void test01() {Person p1("Tom", 18);Person p2("Tom", 18);Person p3("jeery", 18);if (p1==p2){cout << "P1和P2相等" << endl; }else {cout << "P1和P2不相等" << endl;}if (p1!=p3){cout << "P1和P3不相等" << endl; }else {cout << "P1和P3相等" << endl;}
}int main() {test01();system("pause");return 0;
}
4.5.6、函数调用运算符重载
- 函数调用运算符()也可以重载
- 由于重载后使用的方式非常像函数的调用,因此称为仿函数
- 仿函数没有固定写法,非常灵活
- operator()
//匿名函数对象
MyAdd()(100, 100)
#include<iostream>
#include<string>
using namespace std;
class MyPrint {
public://重载函数调用运算符void operator()(string test) {cout << test << endl; }
};
void test01() {MyPrint myPrint;myPrint("hello world");//由于使用起来非常类似于函数调用,因此称为仿函数
}
//仿函数非常灵活,没有固定的写法
//加法类class MyAdd {
public:int operator()(int num1, int num2) {return num1 + num2;}
};void test02() {MyAdd m1;int sum = m1(100, 100);cout << sum << endl;//匿名函数对象cout << MyAdd()(100, 100) << endl;
}
int main() {//test01();test02();system("pause");return 0;
}
相关文章:
C++核心编程--对象篇
4.2、对象 4.2.1、对象的初始化和清理 用于对对象进行初始化设置,以及对象销毁前的清理数据的设置。 构造函数和析构函数 防止对象初始化和清理也是非常重要的安全问题 一个对象或变量没有初始化状态,对其使用后果是未知的同样使用完一个对象或变量&…...
安装php扩展XLSXWriter,解决php导入excel表格时获取日期变成浮点数的方法
安装php扩展XLSXWriter 1、下载安装包 PECL :: Package :: xlswriter #例如选择下载1.3.6版本 2、解压下载包 tar -zxvf xlswriter-1.3.6.tgz 3、进入文件夹,编译 cd xlswriter-1.3.6 phpize ./configure --with-php-config=/usr/local/php7.1/bin/php-config make&am…...
Vue+element开发Simple Admin后端管理系统页面
最近看到各种admin,头大,内容太多,根本不知道怎么改。所以制作了这个项目,只包含框架、和开发中最常用的表格和表单,不用自己从头搭建架构,同时也容易上手二次开发。可以轻松从其他开源项目整合到本项目。项…...
源码编译安装pkg-config
安装环境:银河麒麟 1 到这个网址下载pkg-config源码: Index of /releases (pkg-config.freedesktop.org) 2 解压 3 进入解压后的目录。输入 ./configure 但是报错。 4 根据报错信息,将configure改为: ./configure --with-i…...
游览器找不到服务器上PHP文件的一种原因
最近在练习搭建网站,遇到游览器找不到服务器上的php文件的问题。后来查找发现,apache文档根目录跟apache虚拟主机文档根目录不同,服务器开启了虚拟主机功能。这导致游览器找不到php文件。使用的环境LAMP 里操作系统和软件版本如下:…...
C++之std::function的介绍
C之std::function的介绍 std::function和函数指针的区别介绍std::function 的常见用法包括用法举例 std::function和函数指针的区别介绍 std::function 和函数指针在 C 中都可以用来存储和调用函数,但它们的使用方式和功能有所不同。 函数指针是一种指向函数的指针…...
卷积神经网络学习(一)
CNN应用对象是图像,CNN可被应用于的任务: 1、分类(classification):对图像按其中的物体进行分类,如图像中有人与猫,则图像可分为两类。 2、目标检测(object detection)&a…...
使用KEIL自带的仿真器仿真遇到问题解决
*** error 65: access violation at 0x40021000 : no read permission 修改debug选项设置为下方内容。...
4700 万美元损失,Xn00d 合约漏洞攻击事件分析
4700 万美元损失,Xn00d 合约漏洞攻击事件分析 基础知识 ERC777 ERC777 是 ERC20 标准的高级代币标准,要提供了一些新的功能:运营商及钩子。 运营商功能。通过此功能能够允许第三方账户代表某一合约或者地址 进行代币的发送交易钩子功能。…...
第5讲:v-if与v-show的使用方法及区别
v-if条件判断 v-if是条件渲染指令,它根据表达式的真假来删除和插入元素,它的基本语法如下: v-if “expression” expression是一个返回bool值的表达式,表达式可以是一个bool属性,也可以是一个返回bool的运算式 &#…...
C理解(一):内存与位操作
本文主要探讨C语言的内存和为操作操作相关知识。 冯诺依曼结构和哈佛结构 冯诺依曼结构:数据和代码放在一起,便于读取和修改,安全性低 哈佛结构是:数据和代码分开存放,安全性高,读取和修麻烦 内存 内存是用来存储全局变量、局…...
ESP8266使用记录(四)
放上最终效果 ESP8266&Unity游戏 整合放进了坏玩具车遥控器里 最终只使用了mpu6050的yaw数据,因为roll值漂移…… 使用了https://github.com/ElectronicCats/mpu6050 整个流程 ESP8266取MPU6050数据,处理后通过udp发送给Unity显示出来 MPU6050_Z…...
云原生Kubernetes:K8S安全机制
目录 一、理论 1.K8S安全机制 2.Authentication认证 3.Authorization授权 4.Admission Control准入控制 5.User访问案例 6.ServiceAccount访问案例 二、实验 1.Admission Control准入控制 2.User访问案例 3.ServiceAccount访问案例 三、问题 1.生成资源报错 2.镜…...
【数据结构】归并排序、基数排序算法的学习知识点总结
目录 1、归并排序 1.1 算法思想 1.2 代码实现 1.3 例题分析 2、基数排序 2.1 算法思想 2.2 代码实现 2.3 例题分析 1、归并排序 1.1 算法思想 归并排序是一种采用分治思想的经典排序算法,通过将待排序数组分成若干个子序列,将每个子序列排序ÿ…...
【C++】C++模板进阶 —— 非类型模板参数、模板的特化以及模板的分离编译
📝个人主页:Sherry的成长之路 🏠学习社区:Sherry的成长之路(个人社区) 📖专栏链接:C学习 🎯长路漫漫浩浩,万事皆有期待 上一篇博客:【C】C多…...
HTML的相关知识
1.什么是HTML?基本语法 HTML: Hyper Text Markup Language (超文本标记语言) 超文本?超级文本,例如流媒体,声音、视频、图片等。 标记语言?这种语言是由大量的标签组成。HTML标签参考手…...
基于微信小程的流浪动物领养小程序设计与实现(源码+lw+部署文档+讲解等)
文章目录 前言系统主要功能:具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序(小蔡coding)有保障的售后福利 代码参考源码获取 前言 💗博主介绍:✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计…...
Java后端接口编写流程
💗wei_shuo的个人主页 💫wei_shuo的学习社区 🌐Hello World ! Java后端接口编写流程 Java后端接口编写流程,更具业务逻辑编写Java后端接口,提供给前端访问 实现逻辑流程 POJO:实体类编写 Data B…...
【问题记录】解决“命令行终端”和“Git Bash”操作本地Git仓库时出现 中文乱码 的问题!
环境 Windows 11 家庭中文版git version 2.41.0.windows.1 问题情况 在使用 “命令行终端” 和 “Git Bash” 在本地Git仓库敲击命令时,对中文名称文件显示一连串的数字,如下所示:这种情况通常是由于字符编码设置不正确所引起的 解决办法 设置…...
软考高级之系统架构师之软件需求工程
概述 一个完整的软件生存周期是以需求为出发点。软件需求是指用户对系统在功能、行为、性能、设计约束等方面的期望。 需求开发: 需求获取需求分析需求定义(需求规格说明书)需求验证 需求管理: 变更控制版本控制需求跟踪需求状态跟踪 需…...
使用 Velocity 模板引擎的 Spring Boot 应用
使用 Velocity 模板引擎的 Spring Boot 应用 模板引擎是构建动态内容的重要工具,特别适用于生成HTML、邮件内容、报告和其他文本文档。Velocity是一个强大的模板引擎,它具有简单易用的语法和灵活性。本文将介绍如何在Spring Boot应用中使用Velocity模板…...
mysql的mvcc详解
一 MVCC的作用 1.1 mvcc的作用 1.MVCC(Multiversion Concurrency Control)多版本并发控制。即通过数据行的多个版本管理来实现数据库的并发控制,使得在InnoDB事务隔离级别下执行一致性读操作有了保障。 2.mysql中的InnoDB中实现了MVCC主要…...
FreeRTOS两个死机原因(中断调用接口异常)【杂记】
1、中断回调函数中没有使用中断级API (xxFromISR) 函数 xSemaphoreGiveFromISR(uart_busy,&HighterTask);----正确 xSemaphoreGive(uart_busy);-----错误2、比configMAX_SYSCALL_INTERRUPT_PRIORITY优先级高的中断函数中使用了FreeRTOS的函数 3、临界代码保护后不可调用os…...
【AI视野·今日Robot 机器人论文速览 第四十三期】Thu, 28 Sep 2023
AI视野今日CS.Robotics 机器人学论文速览 Thu, 28 Sep 2023 Totally 37 papers 👉上期速览✈更多精彩请移步主页 Interesting: 📚****触觉力控学习策略,基于触觉的主动推理与力控用于小孔插入任务。提出了姿态控制与插入控制双策略模型。 (from 东京大学…...
批量快捷创建新数组的几种方式
1. for循环, push(比较简单, 就不上代码了) 2.创建空数组,填充null,然后map: function createData() { return new Array(1000) .fill(null) .map((v,i)>({name: name${i1}})) } console.log(createData()) 3.Array.frommap function createData() { return Array.from…...
单目标应用:基于沙丁鱼优化算法(Sardine optimization algorithm,SOA)的微电网优化调度MATLAB
一、沙丁鱼优化算法 沙丁鱼优化算法(Sardine optimization algorithm,SOA)由Zhang HongGuang等人于2023年提出,该算法模拟沙丁鱼的生存策略,具有搜索能力强,求解精度高等特点。 沙丁鱼主要以浮游生物为食,这些生物包括细菌、腔肠…...
基于Halo搭建个人博客
准备 云服务器 安装Docker 开启8090端口 步骤 拉取Halo镜像 docker pull halohub/halo:2.1.0 制作容器并启动 docker run -it -d --name halo -p 8090:8090 -v ~/.halo2:/root/.halo2 halohub/halo:2.1.0 --halo.external-urlhttp://服务器ip:8090/ --halo.security.in…...
DPDK系列之三十一DPDK的并行机制简介
一、并行机制 什么是并行机制?这个很多开发者的眼中,其实是模糊的。可能说起来头头是道,但是细一查究竟,发现都是飘在空中的东西。在前面的“多核和多CPU编程”中,对并行机制已经进行了较深入的分析,这里只…...
【Java】复制数组的四种方式
1. System.arraycopy() 用来将一个数组的(一部分)内容复制到另一个数组里面去。 定义: void arraycopy(Object src, int srcPos, Object dest, int destPos, int length);例: int[] arr1 { 1, 2, 3, 4, 5 }; int[] arr2 new…...
设计模式5、原型模式 Prototype
解释说明:使用原型实例指定待创建对象的类型,并且通过复制这个原型阿里创建型的对象 UML 结构图: 抽象原型(Prototype):规定了具体原型对象必须实现的clone()方法 具体原型(ConcretePrototype&…...
建设中小企业网站/网络营销专业如何
but we cant use it unless you put visual studio in 64bit mode.最近装dlib时候遇到这个问题,很简单就能解决掉 Visual Studio用户通常应该以64位模式执行所有操作。默认情况下,Visual Studio是32位,在其输出和自己的执行中都是如此&…...
上海建设公司网站/seo 页面链接优化
首先第一步,先注册一个github账户密码,这个过程很简单 这里就不讲了。 当我们注册好并登录之后。 在repositories页面,点击new 然后会进入下面这个页面,创建仓库的页面 从上到下,依次要填的是 1.仓库名,2…...
泉州有什么网站是做鞋子批发的/网络推广引流是做什么工作
模版方法模式的抽象父类有两类方法:具体方法、模版方法将具体处理(干活的)的实现交给子类,父类只是定义方法体,子类负责具体处理(干活的)实现;而将处理框架、规则、顺序、流水、各类…...
网站建设的界面风格有哪些/重庆网
论文作者: Enck, William Ongtang, MacHigar McDaniel, Patrick 下一代的开放操作系统不会在个人主机和大型主机上出现,而是在只能手机上。新环境的开放性将会催生许多新应用和市场,以及更大的集合环境。google的android系统是一个被寄予厚望…...
彩票投资理财平台网站建设/深圳专业seo
技术宅改变世界 http://blog.geek18.com 是广州金矿信息科技有限公司的官方博客,主要搜集极客相关的信息和感兴趣的互联网资讯,也有一些编程方面的心得和教程等.转载于:https://www.cnblogs.com/iammatrix/p/5516311.html...
静态网站用什么做最快/广州白云区最新信息
有两个插件可以用 actiBPMActiviti BPMN visualizer 两款插件直接在IDEA插件市场搜索就可以搜到,也可以到官方网站的插件仓库也可以找到。 JetBrains插件市场:https://plugins.jetbrains.com/ 我正在使用的IDEA版本是2020.3,而actiBPM不兼容…...