【黑马程序员】C++封装、对象特性、友元

news2024/11/28 18:40:33

文章目录

  • 类和对象
  • 封装
    • 封装的意义
    • struct和class的区别
    • 成员属性设置为私有
    • 封装练习
      • 设计立方体类
      • 点和圆的关系
  • 对象的初始化和清理
    • 构造函数和析构函数
      • 构造函数
      • 析构函数
    • 构造函数的分类及调用
    • 拷贝构造函数的调用时机
    • 构造函数调用规则
    • 深拷贝与浅拷贝
      • 浅拷贝
      • 深拷贝
    • 初始化列表
    • 类对象作为类的成员
    • 静态成员
      • 静态成员变量
      • 静态成员函数
  • C++ 对象模型和this指针
    • 成员变量和成员函数分开存储
    • this指针
      • `this` 指针具有以下特点:
      • this指针用途
    • 空指针访问成员函数
    • const修饰成员函数
      • 常函数
      • 常对象
  • 友元
    • 使用全局函数做友元
    • 类做友元
    • 成员函数做友元

20240214

类和对象

  • C++面向对象三大特性:封装、继承、多台

  • c++中万事皆对象

封装

封装的意义

  • 将对象
#include <iostream>

using namespace std;

const double PI = 3.14;
//定义一个圆类
class Circle{
// 访问权限
public:
	// 属性
	// 半径
	int m_r;
	// 行为
	// 获取圆的周长
	double getPerimeter() {
		return 2*PI*m_r;
	}
};

int main(){
	// 使用类初始化一个对象
	Circle c;
	// 对象属性赋值
	c.m_r = 2;
	// 调用对象方法获取圆周长
	cout << "圆的周长:" << c.getPerimeter() << endl;
	return 0;
}
  • 控制访问权限

    • public 公共权限,成员在类内可以访问,类外也可以访问

    • protect 保护权限,成员在类内可以访问,类外不可以访问

    • private 私有权限,成员在类内可以访问,类外不可以访问

#include <iostream>
#include <string>

using namespace std;

class Person{
public:
	string name;
protected:
	int age;
private:
	string phone;
public:
	// 类内访问
	void func(){
		name="zs";
		age = 12;
		phone="12345";
	}
};

int main(){
	Person p;
    // 类外访问
	p.name = "ls";
	// error: 'age' is a protected member of 'Person'
	// p.age = 18;
	// error: 'phone' is a private member of 'Person'
	//p.phone = 20;
	return 0;
}

struct和class的区别

  • 唯一区别就是默认的访问权限不同

  • struct默认的访问全向为public权限

  • classs默认的访问全向为private权限

struct P1{
	int age;    // 默认为public权限
};

class P2 {
	int age;    // 默认为private权限
};

int main(){
	// 实例化struct类对象
	P1 p1;
	// 实例化class类对象
	P2 p2;
	p1.age = 1;
	// error: 'age' is a private member of 'P2'
	// p2.age = 2;
	return 0;
}

成员属性设置为私有

  • 优点:

    • 可以自己控制读写权限

    • 对于写权限可以判断数据的有效性

#include <iostream>
#include <string>

using namespace std;

class Person{
public:
	void setName(string name){
		m_name=name;
	}
	string getName(){
		return m_name;
	}
	void setAge(int age){
		// 判断数据有效性
		if (age > 100 || age < 0) {
			return;
		}
		m_age = age;
	}
	int getAge(){
		return m_age;
	}
private:
	string m_name;	// 可读可写
	int m_age;	// 可读
	string m_password;	// 不可读不可写
};

int main(){
	Person p1;
	p1.setName("zs");
	p1.getName();
	p1.setAge(18);
	p1.getAge();
	return 0;
}

封装练习

设计立方体类

  • 求出立方体的面积和体积
#include <iostream>

using namespace std;

class Cube {
public:
	void setEdge(int edge){
		m_edge = edge;
	}

	// 计算面积
	int calcArea() {
		return 6 * m_edge * m_edge;
	}
	// 计算体积
	int calcVolume() {
		return m_edge*m_edge*m_edge;
	}
	// 判断两个立方体是否相同
	bool isSameCube(int edge) {
		return m_edge=edge;
	}
private:
	int m_edge;
};

int main(){
	Cube c1;
	c1.setEdge(2);
	cout << "c1立方体的面积是:" << c1.calcArea() << endl;
	cout << "c1立方体的体积是:" << c1.calcVolume() << endl;
	return 0;
}

点和圆的关系

  • 设计一个圆类和点类,判断点和圆的关系

  • 圆头文件编写circle.hpp

#pragma once
#include "point.hpp"

class Circle{
public:
	void setRadio(int r, int x, int y);
	int getR();
	Point getPoint();
private:
	int m_r;	// 半径
	Point p;	// 圆心
};
  • 点头文件编写point.hpp
#pragma once

class Point {
public:
	void setX(int x);

	void setY(int y);
	int getX();
	int getY();
private:
	int m_x;	// 横坐标
	int m_y;	// 纵坐标
};
  • 源文件编写point_and_circle.cpp
#include <iostream>
#include <cmath>
#include "circle.hpp"
#include "point.hpp"

using namespace std;

void Point::setX(int x) {
	m_x = x;
}

void Point::setY(int y) {
	m_y = y;
}
int Point::getX() {
	return m_x;
}
int Point::getY() {
	return m_y;	
}

void Circle::setRadio(int r, int x, int y) {
	m_r = r;
	p.setX(x);
	p.setY(y);
}
int Circle::getR() {
	return m_r;
}
Point Circle::getPoint() {
	return p;
}

void judgePointAndCircleRelation(Circle& c, Point& p) {
	// 计算点到圆心的距离
	int d = sqrt((p.getX()-c.getPoint().getX())^2+(p.getY()-c.getPoint().getY())^2);
	int r = c.getR();
	if (d == r){
		cout << "点在圆上" << endl;
	} else if (d > r) {
		cout << "点在圆外" << endl;
	} else {
		cout << "点在圆外" << endl;
	}
}

int main() {
	Circle c;
	Point p;
	c.setRadio(2, 0 , 0);
	p.setX(10);
	p.setY(2);
	judgePointAndCircleRelation(c, p);
	return 0;
}

对象的初始化和清理

构造函数和析构函数

  • 由编译器自动调用

  • 如果不写构造函数和析构函数,编译器会自己提供空实现的构造函数和析构函数

构造函数

  • 主要用于创建对象时,为对象成 员赋值

  • 语法:类名() {}

    • 构造函数没有返回值,也不用写void

    • 函数名称和类名相同

    • 构造函数可以有参数,因此可以发生重载

    • 程序在调用对象时会自动调用构造函数,无需手动调用且只会调用一次

析构函数

  • 主要用于对象销毁时执行一些清理工作

  • 语法:~类名() {}

    • 析构函数没有返回值,也不用写void

    • 函数名称和类名相同,在名称前加上~

    • 构造函数不可以有参数,因此也不能发生重载

    • 程序在调用对象时会自动调用构造函数,无需手动调用且只会调用一次

#include <iostream>

using namespace std;

class Person {
public:
	Person() {
		cout << "construct" << endl;
	}
	~Person() {
		cout << "deconstruct" << endl;
	}
};


int main(){
	Person p;
	return 0;
}

构造函数的分类及调用

  • 按参数分类:有参构造、无参构造

  • 按类型分为:普通构造、拷贝构造

  • 按调用方式

    • 括号法

    • 显示法

    • 隐式转换法

#include <iostream>

using namespace std;

class Person{
public:
	Person(){
		cout << "无参构造" << endl;
	}
	Person(int age){
		m_age=age;
		cout << "有参构造" << endl;
	}
	Person(const Person& p){
		m_age=p.m_age;
		cout << "拷贝构造" << endl;
	}
	~Person(){
		cout << "析构函数" << endl;
	}
private:
	int m_age;
};

void test() {
	cout << "===括号法调用===" << endl;
	// 无参构造调用
	Person p;
	// 调用默认构造函数时不要加()
	// Person px() 编译器会将这行代码当成一个函数声明
	// Person px();
	// 有参构造调用
	Person p1(3);
	// 拷贝构
	Person p2(p1);
	cout << "===显示法调用===" << endl;
	Person pp1 = Person(1);
	Person pp2 = Person(pp1);
	// Person(10) 匿名对象,当前行执行完系统会立即回收掉匿名对象
	Person(10);
	// 不要利用拷贝构造函数初始化匿名对象,编译器会认为Person(p) ==> Person p(p),造成p变量重定义
	cout << "===隐式转换法===" << endl;
	Person p4 =10;	// 等价与Person p4=Person(10);
	Person p5 = p4;
}

int main() {
	test();
	return 0;
}

拷贝构造函数的调用时机

  • 使用一个已经创建完毕的对象来初始化另一个对象

  • 值传递的方式给函数参数传值

  • 以值方式返回局部对象

#include <iostream>

using namespace std;

class Person{
public:
	Person(){
		cout << "无参构造" << endl;
	}
	Person(int age){
		m_age=age;
		cout << "有参构造" << endl;
	}
	Person(const Person& p){
		m_age=p.m_age;
		cout << "拷贝构造" << endl;
	}
	~Person(){
		cout << "析构函数" << endl;
	}
private:
	int m_age;
};

// 使用一个已经创建的对象来初始化另一个新对象
void test01() {
	Person p(10);
	Person p1(p);
}

// 值传递方式给函数参数传值
void func(Person p) {

}

void test02() {
	Person p(10);
	func(p);
}

// 以值方式返回局部对象
Person doWork() {
	Person p(1);
	return p;
}

void test03() {
	Person p =doWork();
}


int main(){
	test01();
	test02();
	test03();
	return 0;
}

构造函数调用规则

  • 默认情况下,c++编译器至少会给一个类添加3个函数

    • 默认构造函数(无参函数体为空)

    • 默认析构函数(无参函数体为空)

    • 默认拷贝构造函数,对属性进行值拷贝

  • 构造函数调用规则

    • 如果自定义了有参构造函数,编译器不会在提供默认无参构造函数
    #include <iostream>
    
    using namespace std;
    
    class Person{
    public:
    	Person(int age){
    		m_age=age;
    		cout << "有参构造函数" << endl;
    	}
    	~Person(){
    		cout << "默认析构函数" << endl;
    	}
    	int m_age;
    };
    
    void test01(){
    	Person p; //no matching constructor for initialization of 'Person'
    }
    
    int main(){
    	test01();
    	return 0;
    }
    
    • 但是会提供默认拷贝构造
    #include <iostream>
    
    using namespace std;
    
    class Person{
    public:
    	Person(){
    		cout << "默认构造函数" << endl;
    	}
    	Person(int age){
    		m_age=age;
    		cout << "有参构造函数" << endl;
    	}
    	~Person(){
    		cout << "默认析构函数" << endl;
    	}
    	int m_age;
    };
    
    void test01(){
    	Person p;
    	p.m_age=18;
    	Person p1(p); //调用默认拷贝构造
    	cout << p1.m_age << endl;
    }
    
    int main(){
    	test01();
    	return 0;
    }
    
    • 如果自定义了拷贝构造函数,编译器不会在提供其它构造函数
#include <iostream>

using namespace std;

class Person{
public:
	Person(const Person& p){
		m_age=p.m_age;
		cout << "拷贝构造函数" << endl;
	}
	~Person(){
		cout << "默认析构函数" << endl;
	}
	int m_age;
};

void test01(){
	//no matching constructor for initialization of 'Person'
    Person p;
	Person p1(18);
}

int main(){
	test01();
	return 0;
}

深拷贝与浅拷贝

  • 如果类中有属性需要在对上开辟空间,一定要自己实现拷贝构造函数

浅拷贝

  • 简单的赋值拷贝操作

  • 浅拷贝存在问题:堆区的内存重复释放

#include <iostream>

using namespace std;

class Person{
public:
        Person(){
                cout << "默认构造" << endl;
        }
        Person(int age, int height){
                m_age = age;
                // 使用new关键字在堆上开辟
                m_height=new int(height);
                cout << "赋值拷贝构造" << endl;
        }
        ~Person(){
                if (m_height != NULL) {
                        delete m_height;
                }
                cout << "析构函数" << endl;
        }
        int m_age;
        int *m_height;
};

void test(){
        Person p(18, 170);
        // 调用默认拷贝构造函数,使用的是浅拷贝的方式,析构释放堆上的内存会出错
        Person p1(p);
}

int main(){
        test();
        return 0;
}

在这里插入图片描述

深拷贝

  • 在堆区重新申请空间,进行拷贝操作

  • 解决深拷贝,重复释放对上内存导致的panic

#include <iostream>

using namespace std;

class Person{
public:
	Person(){
		cout << "默认构造" << endl;
	}
	Person(int age, int height){
		m_age = age;
		// 使用new关键字在堆上开辟
		m_height=new int(height);
		cout << "赋值拷贝构造" << endl;
	}
	Person (const Person& p) {
		m_age=p.m_age;
		m_height = new int(*p.m_height);
	}
	~Person(){
		if (m_height != NULL) {
			delete m_height;
		}
		cout << "析构函数" << endl;
	}
	int m_age;
	int *m_height;
};

void test1() {
	Person p(18, 170);
        // 调用自定义实现的深拷贝构造函数
        Person p1(p);
}

int main(){
	test1();
	return 0;
}

初始化列表

  • C++提供初始化列表语法,用来初始化 属性

  • 语法:构造函数():属性1(值1),属性2(值2)...

#include <iostream>
#include <string>

using namespace std;

class Person{
public:
	// 写死了函数必须按这种方式传递
	Person():m_name("zs"),m_age(10){
		cout << "无参初始化列表" << endl;
	}
	// 按照参数方式传入
	Person(int age, string name):m_age(age),m_name(name) {
		cout << "有参初始化列表" << endl;
	}
	~Person(){
		cout << "析构函数" << endl;
	}
	int m_age;
	string m_name;
};

int main(){
	Person p;
	cout << "姓名:" << p.m_name << " 年龄:" << p.m_age << endl;
	Person p1(18, "ls");
	cout << "姓名:" << p1.m_name << " 年龄:" << p1.m_age << endl;
	return 0;
}

类对象作为类的成员

  • C++中的成员可以是另一个类的对象,我们称该成员为对象成员

  • 构造的顺序:先调用成员的构造函数,在调用本类的构造函数,析构与构造的顺序相反

#include <iostream>
#include <string>

using namespace std;

class Phone{
public:
	Phone(string name):pname(name){
		cout << "Phone构造函数" << endl;
	}
	~Phone(){
		cout << "Phone析构函数" << endl;
	}
	string pname;
};

class Person{
public:
	Person(string name, string pname):m_name(name),m_phone(pname){
		cout << "Person构造函数" << endl;
	}
	~Person() {
		cout << "Person析构函数" << endl;
	}
	string m_name;
	Phone m_phone;
};

void test(){
	Person p("zs", "iphone");
}

int main(){
	test();
	return 0;
}

静态成员

  • 静态成员就是在成员变量和成员函数前面加上static关键字

  • 静态成员也是有访问权限的

静态成员变量

  • 所有对象共享同一份数据

  • 在编译阶段分配内存

  • 类内声明,类外初始化

  • 访问方式:通过对象访问;通过类名访问

#include <iostream>

using namespace std;

class Person{
public:
        // 类内声明
        static int age;
private:
        // 静态成员也是有访问权限的
        static int a;
};

// 类外初始化,Person::告诉编译器这是这个作用域下的变量
int Person::age=100;
int Person::a = 12;

void test(){
        Person p;
        cout << p.age << endl;
        Person p1;
        p1.age=18;
        cout << p.age << endl;
}

void test01(){
        // 静态成员变量不属于某个对象,所有对象都共享同一份数据,因此静态成员变量有两种访问方式
        // 方式一
        Person p;
        cout << "通过对象访问:" << p.age << endl;
        // 方式二
        cout << "通过类名访问:" << Person::age << endl;
}

void test02(){
        // 静态成员也是有访问权限的
        // error: 'a' is a private member of 'Person'
        // cout << "访问静态私有变量访问不到" << Person::a << endl;
}

int main(){
        test();
        test01();
        test02();
        return 0;
}

静态成员函数

  • 所有对象共享同一个函数

  • 静态成员函数只能访问静态成员变量

#include <iostream>

using namespace std;

class Person{
public:
        // 静态成员函数
        static void func(){
                // 静态成员函数只能访问静态变量
                m_A = 1;
                // 不能区分非静态变量是属于那个对象的成员
                // error: invalid use of member 'm_B' in static member function
                // m_B = 2;
                cout << "static void func() 调用" << endl;
        }
        static int m_A;
        int m_B;
};
int Person::m_A=1;

// 静态成员函数调用方式
void test(){
        // 使用对象调用
        Person p;
        p.func();
        // 使用类名调用
        Person::func();
}

int main(){
        test();
        return 0;
}

C++ 对象模型和this指针

成员变量和成员函数分开存储

  • 空类占用内存大小为1,用来占位

  • 非静态成员变量属于类上的对象

  • 静态成员变量、非静态成员函数(非静态成员函数也是只有一份函数实例)、静态成员函数都不属于类上的对象

#include <iostream>

using namespace std;

class A {};

class B {
	// 非静态成员变量属于类上的对象
	int a;
};

class C {
	// 非静态成员变量属于类上的对象
	int a;
	// 静态成员变量不属于类的对象上
	static int b;
};

class D {
	// 非静态成员变量属于类上的对象
	int a;
	// 静态成员变量不属于类的对象上
	static int b;
	void func(){}
};


class E {
	// 非静态成员变量属于类上的对象
	int a;
	// 静态成员变量不属于类的对象上
	static int b;
	void func(){}
	static void func1(){}
};


void test(){
	A a;
	// 空对象占用空间大小:1
	// C++编译器会给每个空对象也分配一个字节空间,是为了区分空对象占内存的位置
	// 每个空对象也应该有一个独一无二的内存地址
	cout << "空类的大小是:" << sizeof(a) << endl;
}

void test1(){
	B b;
	cout << "只有一个int类型非静态成员变量的类的大小是:" << sizeof(b) << endl;
}

void test2(){
	C c;
	cout << "一个int类型非静态成员变量和一个int类型的静态成员变量的类的大小是:" << sizeof(c) << endl;
}

void test3(){
	D d;
	// 普通成员函数不属于类上的对象
	cout << sizeof(d) << endl;
}

void test4() {
	E e;
	// 静态成员函数不属于类上的对象
	cout << sizeof(e) << endl;
}

int main(){
	test();
	test1();
	test2();
	test3();
	test4();
	return 0;
}

this指针

  • this指针指向被调用成员函数所属的对象

  • this指针是隐含每一个非静态成员函数的一种指针

  • this指针不需要定义,直接使用即可

this 指针具有以下特点:

  • this 指针是一个指针,它存储对象的地址。

  • this 指针是一个常量指针,不能修改它所指向的地址。

  • this 指针在非静态成员函数内部是可用的,它允许你通过 this->(*this). 访问对象的成员变量和成员函数。

  • this 指针的类型是指向类类型的常量指针。例如,如果对象属于 Person 类,则 this 的类型是 Person* const

this指针用途

  • 当形参和成员变量同名时可以使用this指针来区分

  • 在类的非静态成员函数中返回对象本身,return *this;

#include <iostream>

using namespace std;

class Person{
public:
	Person(int age){
		// 使用this指针解决命名冲突
		this->age=age;
	}
	// 返回对象本身时需要使用引用类型
	// 如果返回的不是引用,那么外层调用位置在赋值时就会调用拷贝构造生成新的临时对象
	Person& PersonAddAge(Person& p) {
		this->age += p.age;
		return *this;
	}
	int age;
};

void test(){
	Person p(18);
	cout << p.age << endl;
}

void test1(){
	Person p1(10);
	Person p2(10);
	// 链式编程思想
	p1.PersonAddAge(p2).PersonAddAge(p2).PersonAddAge(p2).PersonAddAge(p2);
	cout << p1.age << endl;
}

int main(){
	test();
	test1();
	return 0;
}

空指针访问成员函数

  • 空指针是可以正常的访问成员函数的
#include <iostream>

using namespace std;

class Person{
public:
        void showClassName() {
                cout << "this is Person class" << endl;
        }

        void showPersonAge() {
                // 增加代码的健壮性
                ifthis == NULL{
                        return;
                }
                // 默认类中的成员属性都会有一个默认的this指针,即this->age
                cout << age << endl;
        }
        int age;
};

void test(){
        Person * p = NULL;
        p->showClassName();
        // p->showPersonAge() 空指针奔溃,因为内部使用的是this->age,而this是一个NULL
        p->showPersonAge();
}

int main(){
        test();
        return 0;
}

const修饰成员函数

常函数

  • 成员函数后加上const之后,我们称这个函数为常函数

  • 常函数内不可以修改成员属性

  • 成员属性声明时加上mutable后,在常函数中依然可以修改

常对象

  • 声明对象前加const称该对象为常对象

  • 常对象只能调用常函数

#include <iostream>

using namespace std;

class Person{
public:
	Person(){}
	// this指针相当于Person* const this,this指向的对象不能更改
	// 在函数后面加上const相当于 const Person* const this,this指向的对象和值都不能改
	void showPerson() const {
		// age = 10;
		// a有mutable修饰所以可以更改
		a = 1;
	}
	void func(){}
	int age;
	mutable int a;
};

// 常函数测试
void test(){
	Person p;
	p.showPerson();
}

// 常对象测试
void test1(){
	// 在对象前加const,变为常对象
        const Person p;
        // p.age =1;
	// a是mutable修饰的变量,在常对象下也可以修改
	p.a = 1;

	// 常对象只能调用常函数
	p.showPerson();
	// 常对象不能调用普通函数,因为在常对象限制了只能修改mutable修饰的变量,而在普通函数中可以修改任意变量
	// p.func();
}

int main(){
	test();
	test1();
	return 0;
}

友元

  • 友元的目的就是让一个类或者函数访问另一个类中的私有成员

使用全局函数做友元

#include <iostream>
#include <string>

using namespace std;

class Building{
	// 声明GoodGay为Building的友元函数,这样在GoodGay函数中可以访问Building的私有成员变量
	friend void GoodGay(Building& building);
public:
	Building(){
		sittingRoom = "sittingRoom";
		bedingRoom = "bedingRoom";
	}
public:
	string sittingRoom;
private:
	string bedingRoom;
};

// 全局函数想访问类的私有成员
void GoodGay(Building& building){
	cout << "Good Gay 正在访问:" << building.sittingRoom << endl;
	cout << "Good Gay 正在访问:" << building.bedingRoom << endl;
}

void test(){
	Building b;
	GoodGay(b);
}

int main(){
	test();
	return 0;
}

类做友元

  • 让友元类可以访问另一个类中的所有成员函数
#include <iostream>
#include <string>
using namespace std;

class Building;
class GoodGay {
public:
	GoodGay();
	// visit()函数访问Building中的属性
	void visit();
	Building* b;
};

class Building{
	// 声明GoodGay类是Building的友元类
	friend class GoodGay;
public:
	Building();
public:
	string sittingRoom;
private:
	string bedingRoom;
};

// 类外实现成员函数
GoodGay::GoodGay(){
	// 构造函数中创建一个Building的对象
	b=new Building;
}
void GoodGay::visit(){
	cout << "GoodGay class正在访问: " << b->sittingRoom << endl;
	cout << "GoodGay class正在访问: " << b->bedingRoom << endl;
}

Building::Building(){
	sittingRoom="sittingRoom";
    bedingRoom="bedingRoom";
}
// 测试
void test(){
	GoodGay gg;
	gg.visit();
}

int main(){
	test();
	return 0;
}

成员函数做友元

  • 让类中的某些成员函数可以访问另一个类中的私有成员变量
#include <iostream>
#include <string>
using namespace std;

class Building;
class GoodGay {
public:
	GoodGay();
	// visit()函数访问Building中的私有属性
	void visit();
	// visit1()函数不可以访问Building中的私有属性
	void visit1();
	Building* b;
};

class Building{
	// 声明GoodGay类下的visit函数作为Building类的友元函数
	friend void GoodGay::visit();
public:
	Building();
public:
	string sittingRoom;
private:
	string bedingRoom;
};

// 类外实现成员函数
GoodGay::GoodGay(){
	// 构造函数中创建一个Building的对象
	b=new Building;
}
void GoodGay::visit(){
	cout << "GoodGay visit正在访问: " << b->sittingRoom << endl;
	cout << "GoodGay visit正在访问: " << b->bedingRoom << endl;
}

void GoodGay::visit1(){
        cout << "GoodGay visit1正在访问: " << b->sittingRoom << endl;
}

Building::Building(){
	sittingRoom="sittingRoom";
        bedingRoom="bedingRoom";
}

void test(){
	GoodGay gg;
	gg.visit();
	gg.visit1();
}

int main(){
	test();
	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1448225.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

matplotlib雷达图制作具体步骤

此次我们制作的是关于护肤品下的畅销品类雷达图&#xff0c;数据如下&#xff1a; 数据预览&#xff1a; 一、代码展示 import pandas as pd import numpy as np import matplotlib.pyplot as plt plt.rcParams[font.sans-serif][SimHei] adress"D:/pandas练习文件/雷达…

JAVA设计模式之解释器模式详解

解释器模式 1 解释器模式介绍 解释器模式使用频率不算高&#xff0c;通常用来描述如何构建一个简单“语言”的语法解释器。它只在一些非常特定的领域被用到&#xff0c;比如编译器、规则引擎、正则表达式、SQL 解析等。不过&#xff0c;了解它的实现原理同样很重要&#xff0…

零基础学编程怎么入手,中文编程工具构件箱之星空构件用法教程,系统化的编程视频教程上线

零基础学编程怎么入手&#xff0c;中文编程工具构件箱之星空构件用法教程&#xff0c;系统化的编程视频教程上线 一、前言 今天给大家分享的中文编程开发语言工具资料如下&#xff1a; 编程入门视频教程链接 http://​ https://edu.csdn.net/course/detail/39036 ​ 编程…

Java17之使用Lambda表达式对对象集合中指定的字段进行排序

Java17之使用Lambda表达式对对象集合中指定的字段进行排序 文章目录 Java17之使用Lambda表达式对对象集合中指定的字段进行排序1. 集合对象排序1. Java实体类2. 正序排序3.倒序排序 1. 集合对象排序 Java8起可用 List 的 sort 方法进行排序&#xff0c;形参为函数式接口Compara…

C++ //练习 6.12 改写6.2.1节中练习6.10(第188页)的程序,使用引用而非指针交换两个整数的值。你觉得哪种方法更易于使用呢?为什么?

C Primer&#xff08;第5版&#xff09; 练习 6.12 练习 6.12 改写6.2.1节中练习6.10&#xff08;第188页&#xff09;的程序&#xff0c;使用引用而非指针交换两个整数的值。你觉得哪种方法更易于使用呢&#xff1f;为什么&#xff1f; 环境&#xff1a;Linux Ubuntu&#x…

Docker关于conda环境的导出和导入

Docker关于conda环境的导出和导入 1、常用命令&#xff1a;2、环境导出&#xff1a;3、两个服务器之间的文件传输命令&#xff1a;4、环境导入&#xff1a;5、快速进入容器6、其他问题解决记录&#xff1a; 1、常用命令&#xff1a; docker pull -- 从远程仓库将镜像下载至本地…

医疗相关名词,医疗名词整理

1.系统类&#xff1a; HIS Hospital Information System&#xff0c;医院信息系统&#xff0c;在国际学术界已公认为新兴的医学信息学(Medical Informatics)的重要分支。美国该领域的著名教授Morris.Collen于1988年曾著文为医院信息系统下了如下定义&#xff1a;利用电子计算…

[Linux开发工具]项目自动化构建工具-make/Makefile

&#x1f4d9; 作者简介 &#xff1a;RO-BERRY &#x1f4d7; 学习方向&#xff1a;致力于C、C、数据结构、TCP/IP、数据库等等一系列知识 &#x1f4d2; 日后方向 : 偏向于CPP开发以及大数据方向&#xff0c;欢迎各位关注&#xff0c;谢谢各位的支持 目录 1.背景2.依赖关系和依…

error An unexpected error occurred: “https://registry.npm.taobao.org

背景&#xff1a; 想使用yarn命令结果报错 问题原因&#xff1a; 原来证书到期了 http://registry.npm.taobao.org/ 把这个放到浏览器搜索的时候自动换成https://registry.npmmirror.com/ 方案&#xff1a; npm cache clean --forcenpm config set registry https://registry…

Windows 虚拟桌面信息(一)分析注册表

目录 前言 一、理论分析 二、代码实现 总结 本文为原创文章&#xff0c;转载请注明出处&#xff1a; https://blog.csdn.net/qq_59075481/article/details/136110636 前言 Win 10/11 的虚拟桌面微软暂时没有开放接口&#xff0c;有很多信息对开发者是闭塞的&#xff0c;…

Qt QWidget以及各种控件、布局 核心属性(适合入门使用时查询)

目录 1. QWidget核心属性 2. 按钮类控件 2.1 PushButton 核心属性 2.2 RadioButton 核心属性 2.3 CheckBox 和 Tool Button 核心属性 3. 显示类控件 3.1 Label 核心属性 3.2 LCDNumber 核心属性 3.3 ProgressBar 核心属性 3.4 Calendar Widget 核心属性 4. 输入类控…

Photoshop 中的“彩蛋”

在 Photoshop 中隐藏了几个“彩蛋” Easter Eggs&#xff0c;是开发者留下的小秘密或玩笑功能&#xff0c;也许是他们在紧张的开发过程中的一种自我调节吧&#xff0c;就如复活节彩蛋一样&#xff0c;同样也可以给 Photoshop 的用户们带来一点小“惊喜”。 这些彩蛋通常以有趣的…

上位机图像处理和嵌入式模块部署(借鉴与学习)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 对于很多学院派的同学来说&#xff0c;他们对市场的感觉一般是比较弱的。如果写一个软件的话&#xff0c;或者说开发一个项目的话&#xff0c;他们…

【C++关联式容器】unordered_map

目录 unordered_map 1. pair类型 2. 关联式容器额外的类型别名 3. 哈希桶 4. 无序容器对关键字类型的要求 5. Member functions 5.1 constructor、destructor、operator 5.1.1 constructor 5.1.2 destructor 5.1.3 operator 5.2 Capacity ​5.2.1 empty 5.2.2 si…

C/C++内存管理:new、delete功能及原理实现

目录 一、C/C内存分布 二、C中内存管理方式 2.1new/delete操作内置类型 2.2 new和delete操作自定义类型 三、operator new与operator delete函数 四、new和delete的实现原理 4.1内置类型 4.2自定义类型 五、定位new 一、C/C内存分布 int globalVar 1; static int sta…

Java学习第十三节之三种初始化和内存分析

三种初始化 package array;public class ArrayDemo02 {public static void main(String[] args) {//静态初始化&#xff1b;创建赋值int[] a {1, 2, 3, 4, 5, 6, 7, 8};System.out.println(a[0]);for (int i 0; i <a.length; i) {System.out.println(a[i]);}//动态初始化…

你的电脑关机吗

目录 程序员为什么不喜欢关电脑&#xff1f; 电脑长时间不关机会怎样? 电脑卡顿 中度风险 硬件损耗 能源浪费 散热问题 软件问题 网络安全问题 程序员为什么不喜欢关电脑&#xff1f; 大部分人都会选择将电脑进行关机操作。其实这不难理解&#xff0c;毕竟人类都需要…

Qt初使用(使用Qt创建项目,在创建的项目中添加类,Qt中输出内容到控制台,设置窗口大小和窗口标题,Qt查看说明文档)

目录 一.创建带模板的项目新建项目运行在文件中查看该项目文件 二.在创建好的项目中添加类三.创建空项目&#xff08;不使用自带的模板&#xff09;四.Qt中输出内容到控制台五.设置窗口大小 , 窗口标题 ,固定窗口大小QWidget组件的说明 六.Pro文件帮助文档 按windows键&#xf…

1_opencv3环境搭建与测试

之前2020年5月写过一次&#xff0c;时隔3年多&#xff0c;有机会再重新写一次。相比之前&#xff0c;应该是有一点儿进步的。之前是使用默认安装路径&#xff0c;所以无需配置共享库的搜索路径。这次是自定义安装路径&#xff0c;略有区别。随着写程序的时间增长&#xff0c;编…

LeetCode Python - 14.最长公共前缀

目录 题目答案运行结果 题目 编写一个函数来查找字符串数组中的最长公共前缀。 如果不存在公共前缀&#xff0c;返回空字符串 “”。 示例 1&#xff1a; 输入&#xff1a;strs [“flower”,“flow”,“flight”] 输出&#xff1a;“fl” 示例 2&#xff1a; 输入&#xff…