【C++笔记总结】面向对象编程——封装 |C++

文章目录

  • 前言
  • 一、类的封装
    • 1.1、公有,私有,保护
    • 1.2、类的定义和类的实现相分离
    • 1.3、构造函数,析构函数,拷贝构造函数
    • 1.4、静态数据成员和静态成员函数
    • 1.5、友元函数,友元类
  • 二、类的实现——对象
    • 2.1、对象的静态分配,动态分配(堆对象)
    • 2.2、子对象
    • 2.3、this指针


前言

此文开启一个系列,旨在秋招前将所有C++笔记进行汇总总结。
参考答案:chatgpt

一、类的封装

1.1、公有,私有,保护

类中的数据称之为数据成员,类中的函数称之为成员函数
在C++中,类的成员变量和成员函数可以被访问控制符所限制,这些访问控制符分别是公有(public)、保护(protected)和私有(private)。举例1.1如下:

#include <iostream>class MyClass {
public:void setData(int shuru) {privateData = shuru; // 类内使用私有成员:将参数赋值给私有成员protectedData = shuru * 2; // 类内使用保护成员:将参数的两倍赋值给保护成员std::cout << "setData: privateData = " << privateData << ", protectedData = " << protectedData << std::endl;// 在类的成员函数中访问保护成员和私有成员privateFunc();protectedFunc();}int getData() {return privateData; // 类内使用私有成员::直接使用私有成员的名称}protected:int protectedData; // 保护成员void protectedFunc() {std::cout << "This is a protected function." << std::endl;} // 保护成员函数private:int privateData; // 私有成员void privateFunc() {std::cout << "This is a private function." << std::endl;} // 私有成员函数
};int main() {MyClass obj;//对象obj.setData(1234);//公有方法,可以在类外访问std::cout << "Data: " << obj.getData() << std::endl; 公有方法,可以在类外访问// obj.privateData = 456; // 私有成员不能在类的外部访问// obj.privateFunc(); // 私有函数不能在类的外部访问// obj.protectedData = 789; // 不能在类的外部访问保护成员// obj.protectedFunc(); // 保护函数不能在类的外部访问return 0;
}

1)公有成员函数可以在类的外部访问,相当于是类的外部接口。;私有成员函数和保护成员函数不能在类的外部访问。
2)私有成员和保护成员的区别在于,私有成员只能在当前类的成员函数中访问,保护成员可以在当前类的成员函数和派生类的成员函数中访问。
3)公有成员函数可以访问类的所有成员,私有成员函数和保护成员函数也可以访问类的所有成员。

1.2、类的定义和类的实现相分离

在大型的C++工程文件里,类的定义和实现经常这样分开:(下面分成了三个文件)
MyClass.h:

MyClass.h:
#ifndef MYCLASS_H
#define MYCLASS_Hclass MyClass {
public:void setData(int shuru);int getData();protected:int protectedData;void protectedFunc();private:int privateData;void privateFunc();
};#endif

如果你在一个源文件中多次使用了 #include “myheader.h”,那么这个头文件就会被多次包含。
如果一个头文件被多次包含,就会出现重复定义的问题,导致编译错误。为了避免这种问题,通常会在头文件的开头加上条件编译指令,例如 #ifndef 和 #define,来防止头文件的重复包含。这样可以保证头文件只会被包含一次,避免重复定义的问题。

MYCLASS_H 是一个头文件的命名规则,通常用于防止同一文件中同一头文件的重复包含。这个命名规则是由以下步骤组成的:

将头文件名转换为大写字母形式,例如 myclass.h 变为 MYCLASS.H。

在文件名前面加上一个下划线,例如 MYCLASS.H 变为 _MYCLASS.H。

在文件名后面加上一个宏定义,例如 _MYCLASS.H 变为 _MYCLASS_H。

这个命名规则可以有效避免同一头文件在同一文件中的重复包含,同时也可以使头文件的名字更加清晰易懂。当然,这个命名规则并不是强制性的,你可以根据自己的需求来命名头文件。

_MYCLASS.H,_MYCLASS_H等的头文件的命名规则可以有很多种,但是只要在同一项目中保持一致即可。这样可以避免同名头文件的冲突,也方便项目的维护和管理。通常情况下,团队中的成员会约定一套命名规则,然后在整个项目中统一使用。这样可以让代码更加规范化和易于维护。

MyClass.cpp:

MyClass.cpp:
#include "MyClass.h"
#include <iostream>void MyClass::setData(int shuru) {privateData = shuru; // 类内使用私有成员:将参数赋值给私有成员protectedData = shuru * 2; // 类内使用保护成员:将参数的两倍赋值给保护成员std::cout << "setData: privateData = " << privateData << ", protectedData = " << protectedData << std::endl;// 在类的成员函数中访问保护成员和私有成员privateFunc();protectedFunc();
}int MyClass::getData() {return privateData; // 类内使用私有成员::直接使用私有成员的名称
}void MyClass::protectedFunc() {std::cout << "This is a protected function." << std::endl;
} // 保护成员函数void MyClass::privateFunc() {std::cout << "This is a private function." << std::endl;
} // 私有成员函数

main.cpp:

main.cpp:
#include <iostream>
#include "MyClass.h"int main() {MyClass obj;obj.setData(1234);std::cout << "Data: " << obj.getData() << std::endl;// obj.privateData = 456; // 私有成员不能在类的外部访问// obj.privateFunc(); // 私有函数不能在类的外部访问// obj.protectedData = 789; // 不能在类的外部访问保护成员// obj.protectedFunc(); // 保护函数不能在类的外部访问return 0;
}

这样做的好处有很多:
1)使代码更加清晰和易于维护。类的界面和实现分开,可以更加清晰地区分哪些是公共接口,哪些是实现细节,方便用户和开发人员理解和使用。
2)提高代码的可重用性。将类的实现与界面分离,可以方便地将类的实现部分复用到其他项目中,而不必担心可能引入的冲突和问题。
3)增加代码的安全性。将类的实现细节隐藏起来,可以防止外部代码直接访问类的私有数据和私有方法,从而提高代码的安全性。
4)降低代码的耦合度。类的界面和实现分离,可以使类的实现部分与其他代码解耦,从而降低代码的耦合度,提高代码的可维护性和可扩展性。

在终端里可以使用下面指令执行:将MyClass.cpp文件编译成目标文件,并将其与main.cpp文件一起链接成可执行文件,才能正确运行程序。

g++ -c MyClass.cpp -o MyClass.o 
g++ main.cpp MyClass.o -o main
./main.exe

当然这个算比较简单的了,复杂一些需要上Cmake

1.3、构造函数,析构函数,拷贝构造函数

构造函数和析构函数是 C++ 中特殊的成员函数,它们分别在对象构造和析构时被调用。
构造函数的主要作用是初始化对象的成员变量,为对象提供一个合理的初始状态。当我们创建一个对象时,编译器会自动调用对象的构造函数。如果我们没有定义构造函数,编译器会生成一个默认构造函数,它不做任何事情。但如果我们需要在对象创建时进行一些初始化操作,就需要定义自己的构造函数。
析构函数的主要作用是在对象销毁时释放资源,例如关闭文件、释放内存等。当对象被销毁时,编译器会自动调用对象的析构函数。如果我们没有定义析构函数,编译器会生成一个默认析构函数,它不做任何事情。但如果我们需要在对象销毁时进行一些清理操作,就需要定义自己的析构函数。
总之,构造函数和析构函数是 C++ 中非常重要的特殊成员函数,它们分别在对象构造和析构时被调用,用于初始化对象的成员变量和释放对象占用的资源。

例1.1加入构造函数和析构函数,得到例1.2,可以感受一下构造函数和析构函数的作用:

#include <iostream>
using namespace std;class MyClass {
public:MyClass(int data) : privateData(data) {protectedData = data * 2;//初始化变量cout << "MyClass constructor called." << endl;}~MyClass() {cout << "MyClass destructor called." << endl;}void setData(int shuru) {privateData = shuru;protectedData = shuru * 2;cout << "setData: privateData = " << privateData << ", protectedData = " << protectedData << endl;privateFunc();protectedFunc();}int getData() {return privateData;}protected:int protectedData;void protectedFunc() {cout << "This is a protected function." << endl;}private:int privateData;void privateFunc() {cout << "This is a private function." << endl;}
};int main() {MyClass obj(100);obj.setData(12345);cout << "Data: " << obj.getData() << endl;return 0;
}

这是一个构造函数的初始化列表,用于初始化私有成员变量privateData。privateData(data)表示将传入的参数data赋值给私有成员变量privateData。这种方式比在构造函数的函数体中直接赋值更高效,因为它避免了在构造函数体中再次对成员变量进行初始化。

当然一个类中,构造函数的形态不止一种,下面是一个例子:

#include <iostream>
using namespace std;class MyClass {
public:MyClass() : privateData(0), protectedData(0) {cout << "MyClass default constructor called." << endl;}MyClass(int data) : privateData(data) {protectedData = data * 2;cout << "MyClass constructor with one parameter called." << endl;}MyClass(int data1, int data2) : privateData(data1), protectedData(data2) {cout << "MyClass constructor with two parameters called." << endl;}~MyClass() {cout << "MyClass destructor called." << endl;}void setData(int shuru) {privateData = shuru;protectedData = shuru * 2;cout << "setData: privateData = " << privateData << ", protectedData = " << protectedData << endl;privateFunc();protectedFunc();}int getData() {return privateData;}protected:int protectedData;void protectedFunc() {cout << "This is a protected function." << endl;}private:int privateData;void privateFunc() {cout << "This is a private function." << endl;}
};int main() {MyClass obj1;MyClass obj2(100);MyClass obj3(100, 200);obj2.setData(12345);cout << "Data: " << obj2.getData() << endl;return 0;
}

这个代码中,我们添加了一个默认构造函数MyClass(),一个带有一个参数的构造函数MyClass(int data),和一个带有两个参数的构造函数MyClass(int data1, int data2)。同时,我们也修改了构造函数的输出信息,以便更好地区分它们。
输出结果:
在这里插入图片描述

构造函数和析构函数的关系:

构造函数和析构函数是成对出现的,构造函数用于初始化对象,而析构函数用于清理对象。在对象创建时,构造函数会被调用一次,而在对象销毁时,析构函数会被调用一次。因此,它们是一一对应的。
在程序中,构造函数和析构函数的调用次数取决于对象的创建和销毁。如果只创建了一个对象,那么构造函数和析构函数各被调用一次。如果创建了多个对象,那么每个对象都会调用一次构造函数和析构函数。如果对象是在栈上创建的,那么它们的构造函数和析构函数会在进入和离开作用域时被调用。如果对象是在堆上创建的,那么需要手动调用delete来销毁对象,这时析构函数会被调用。
需要注意的是,如果一个类继承了另一个类,那么在创建和销毁对象时,构造函数和析构函数的调用顺序是从基类到派生类的。也就是说,先调用基类的构造函数,再调用派生类的构造函数;先调用派生类的析构函数,再调用基类的析构函数。

除此之外,还有一种特殊的构造函数:拷贝构造函数
拷贝构造函数是一种特殊的构造函数,用于将一个对象的值复制到另一个对象中。拷贝构造函数的作用是创建一个新对象,并将已有对象的值复制到新对象中。它常用于以下三种情况:
1)用一个已有对象来初始化一个新对象。
2)将一个对象作为参数传递给一个函数。
3)在函数中返回一个对象。
举个例子:

#include <iostream>
using namespace std;class MyClass {
public:MyClass() : privateData(0), protectedData(0) {cout << "MyClass default constructor called." << endl;}MyClass(int data) : privateData(data) {protectedData = data * 2;cout << "MyClass constructor with one parameter called." << endl;}MyClass(int data1, int data2) : privateData(data1), protectedData(data2) {cout << "MyClass constructor with two parameters called." << endl;}MyClass(const MyClass& other) {privateData = other.privateData;protectedData = other.protectedData;cout << "MyClass copy constructor called." << endl;}~MyClass() {cout << "MyClass destructor called." << endl;}void setData(int shuru) {privateData = shuru;protectedData = shuru * 2;cout << "setData: privateData = " << privateData << ", protectedData = " << protectedData << endl;privateFunc();protectedFunc();}int getData() {return privateData;}protected:int protectedData;void protectedFunc() {cout << "This is a protected function." << endl;}private:int privateData;void privateFunc() {cout << "This is a private function." << endl;}
};void func1(MyClass obj) {cout << "func1 called." << endl;
}MyClass func2() {cout << "func2 called." << endl;MyClass obj(456);return obj;
}int main() {MyClass obj1;MyClass obj2(100);MyClass obj3(100, 200);obj2.setData(12345);cout << "Data: " << obj2.getData() << endl;MyClass obj4(obj2);MyClass obj5 = obj3;func1(obj4);MyClass obj6 = func2();return 0;
}

这里添加了一个拷贝构造函数,用于将一个对象的值复制到另一个对象中。同时,我添加了两个函数,一个是将对象作为参数传递给函数,另一个是在函数中返回对象。这两个函数都会自动调用拷贝构造函数。
在 main 函数中,我创建了几个对象,并调用了它们的成员函数。然后,我创建了两个新的对象,一个是通过拷贝构造函数创建的,另一个是通过赋值运算符创建的。最后,我调用了两个函数,一个是将对象作为参数传递给函数,另一个是在函数中返回对象。在这两个函数中,都会自动调用拷贝构造函数。

在这里插入图片描述

在这些情况下,如果没有定义拷贝构造函数,编译器会自动生成一个默认的拷贝构造函数来完成对象的复制。如果需要进行深拷贝,需要自己定义拷贝构造函数。

1.4、静态数据成员和静态成员函数

静态数据成员是指属于类的成员,而不是属于类的对象的成员。它们是在类被定义时被声明的,而不是在类的对象被创建时被定义的。它们被所有该类的对象所共享,因此它们的值在所有对象之间都是相同的。静态数据成员在程序开始时候被创建,在程序结束时被销毁(而不是构造和析构)

静态数据成员的存在有以下几个好处:
与普通成员变量不同,静态数据成员不需要在每个对象中都存储一份。这可以节省内存空间。
静态数据成员可以被所有该类的对象所共享,这使得它们可以用于在类的所有对象之间传递信息。
静态数据成员可以在类的外部被访问,这使得它们可以用于实现类似于全局变量的功能。
静态数据成员可以被用作常量表达式,这使得它们可以用于在编译时计算常量值。

静态成员函数是指在类中使用 static 关键字修饰的成员函数。静态成员函数不依赖于任何对象,可以直接通过类名调用,而不需要创建对象。因此,静态成员函数不能访问非静态成员变量和非静态成员函数,只能访问静态成员变量和静态成员函数。

(示例):

#include <iostream>
using namespace std;class MyClass {
public:MyClass() : privateData(0), protectedData(0) {cout << "MyClass default constructor called." << endl;count++; // 每次创建对象时,对象数量加1}MyClass(int data) : privateData(data) {protectedData = data * 2;cout << "MyClass constructor with one parameter called." << endl;count++; // 每次创建对象时,对象数量加1}MyClass(int data1, int data2) : privateData(data1), protectedData(data2) {cout << "MyClass constructor with two parameters called." << endl;count++; // 每次创建对象时,对象数量加1}MyClass(const MyClass& other) {privateData = other.privateData;protectedData = other.protectedData;cout << "MyClass copy constructor called." << endl;count++; // 每次创建对象时,对象数量加1}~MyClass() {cout << "MyClass destructor called." << endl;count--; // 每次销毁对象时,对象数量减1}void setData(int shuru) {privateData = shuru;protectedData = shuru * 2;cout << "setData: privateData = " << privateData << ", protectedData = " << protectedData << endl;privateFunc();protectedFunc();}int getData() {return privateData;}static int getCount() {return count; // 返回对象数量}protected:int protectedData;void protectedFunc() {cout << "This is a protected function." << endl;}private:int privateData;void privateFunc() {cout << "This is a private function." << endl;}static int count; // 所有对象的数量
};int MyClass::count = 0; // 在类外部初始化静态数据成员void func1(MyClass obj) {cout << "func1 called." << endl;
}MyClass func2() {cout << "func2 called." << endl;MyClass obj(456);return obj;
}int main() {MyClass obj1;MyClass obj2(100);MyClass obj3(100, 200);obj2.setData(12345);cout << "Data: " << obj2.getData() << endl;MyClass obj4(obj2);MyClass obj5 = obj3;cout << "Total objects: " << MyClass::getCount() << endl; // 输出对象数量func1(obj4);MyClass obj6 = func2();cout << "Total objects: " << MyClass::getCount() << endl; // 输出对象数量return 0;
}

静态成员经常用来做计数器的功能,就像上面代码所示。
当然静态数据成员可以被对象引用,比如MyClass::getCount()其实和obj6.getCount()实现的效果差不多,但是:
MyClass::getCount() 是静态调用,不需要创建对象,可以在任何地方调用;

obj6.getCount() 是动态调用,需要先创建对象,然后通过对象名调用。

另外需要注意的是,静态成员函数只能访问静态成员变量和静态成员函数,而不能访问非静态成员变量和非静态成员函数。因此,如果需要访问非静态成员变量或非静态成员函数,就需要通过对象名调用成员函数。

1.5、友元函数,友元类

友元是C++语言中的一个特殊概念,它允许某个函数或类访问另一个类的保护成员和私有成员。C++中的封装性要求类的私有成员和保护成员只能被类的成员函数访问,而友元机制则打破了这个限制,允许某些外部函数或类访问私有成员和保护成员,从而提高了程序的灵活性和可扩展性。

友元函数可以放在类中的任意位置,实现部分放在类外。

友元类是指一个类可以访问另一个类的私有成员和保护成员,这个类就是另一个类的友元类。友元类的声明方式和友元函数类似,需要在类的声明中使用friend关键字进行声明。
友元类可以访问被它所声明的类的私有成员和保护成员,但是它本身并不是被它所声明的类的成员,因此它不能直接访问被它所声明的类的成员变量和成员函数。如果需要访问被它所声明的类的成员变量和成员函数,可以通过类对象或者指针来访问。

下面是一个例子:

#include <iostream>
using namespace std;class MyClass {
public:MyClass() : privateData(0), protectedData(0) {cout << "MyClass default constructor called." << endl;count++; // 每次创建对象时,对象数量加1}MyClass(int data) : privateData(data) {protectedData = data * 2;cout << "MyClass constructor with one parameter called." << endl;count++; // 每次创建对象时,对象数量加1}MyClass(int data1, int data2) : privateData(data1), protectedData(data2) {cout << "MyClass constructor with two parameters called." << endl;count++; // 每次创建对象时,对象数量加1}MyClass(const MyClass& other) {privateData = other.privateData;protectedData = other.protectedData;cout << "MyClass copy constructor called." << endl;count++; // 每次创建对象时,对象数量加1}~MyClass() {cout << "MyClass destructor called." << endl;count--; // 每次销毁对象时,对象数量减1}void setData(int shuru) {privateData = shuru;protectedData = shuru * 2;cout << "setData: privateData = " << privateData << ", protectedData = " << protectedData << endl;privateFunc();protectedFunc();}int getData() {return privateData;}static int getCount() {return count; // 返回对象数量}protected:int protectedData;void protectedFunc() {cout << "This is a protected function." << endl;}private:int privateData;void privateFunc() {cout << "This is a private function." << endl;}static int count; // 所有对象的数量friend void friendFunc(MyClass obj); // 声明友元函数friend class FriendClass; // 声明友元类,FriendClass是Myclass的友元类
};int MyClass::count = 0; // 在类外部初始化静态数据成员void friendFunc(MyClass obj) { // 定义友元函数cout << "friendFunc called, privateData = " << obj.privateData << endl;obj.privateFunc();
}class FriendClass { // 定义友元类
public:void friendClassFunc(MyClass obj) {cout << "FriendClass called, protectedData = " << obj.protectedData << endl;obj.protectedFunc();}
};void func1(MyClass obj) {cout << "func1 called." << endl;friendFunc(obj); // 调用友元函数
}
MyClass func2() {cout << "func2 called." << endl;MyClass obj(456);return obj;
}
int main() {MyClass obj1;MyClass obj2(100);MyClass obj3(100, 200);obj2.setData(12345);cout << "Data: " << obj2.getData() << endl;MyClass obj4(obj2);MyClass obj5 = obj3;cout << "Total objects: " << MyClass::getCount() << endl; // 输出对象数量func1(obj4);FriendClass friendObj; // 创建友元类对象friendObj.friendClassFunc(obj2); // 调用友元类的成员函数MyClass obj6 = func2();cout << "Total objects: " << MyClass::getCount() << endl; // 输出对象数量return 0;}

友元的弊端主要有以下几点:
破坏了封装性:友元可以访问类的私有成员和保护成员,这破坏了封装性,可能会导致类的安全性降低。

可能会导致耦合度增加:友元函数或友元类需要知道类的实现细节,这可能会导致类和友元之间的耦合度增加,使得类的实现变得更加复杂。

友元不具有继承性:如果一个类是另一个类的友元,那么它并不具有继承性,即它不能访问派生类的私有成员和保护成员。
因此,在使用友元时需要慎重考虑,只有在必要的情况下才应该使用友元。

二、类的实现——对象

2.1、对象的静态分配,动态分配(堆对象)

对象内存的静态分配和动态分配是指在程序运行时,对象所占用的内存空间是在编译时确定还是在运行时动态分配的。
静态分配是指在编译时为对象分配固定大小的内存空间,这种方式也称为栈分配。栈是一种先进后出的数据结构,它的内存分配和释放是由系统自动完成的,程序员不需要手动管理内存。静态分配的优点是速度快,缺点是内存空间固定,不够灵活,无法动态扩展。
动态分配是指在程序运行时根据需要动态地分配内存空间,这种方式也称为堆分配。堆是一种动态分配内存的方式,程序员需要手动管理内存的分配和释放。动态分配的优点是灵活性强,可以动态地扩展内存空间,缺点是速度较慢,容易出现内存泄漏和内存碎片等问题。
对于对象的内存分配,一般情况下建议使用动态分配,尤其是对象的大小不确定或者需要动态扩展时。但是在某些情况下,静态分配也是一种不错的选择,例如对象的大小固定且较小,或者需要频繁创建和销毁对象时,使用静态分配可以提高程序的运行效率。

静态分配的对象也称为自动变量(automatic variable)、栈变量(stack variable)或局部变量(local variable)。它们的内存在程序编译时就已经分配好了,作用域只在当前代码块中,当代码块执行完毕时,它们会自动被销毁。
动态分配的对象也称为堆对象(heap object)、动态对象(dynamic object)或者动态内存分配对象(dynamically allocated object)。它们的内存空间在程序运行时动态分配,作用域可以跨越多个代码块,需要手动管理内存的分配和释放。

下面是堆对象建立删除,堆对象数组建立删除的例子

#include <iostream>
using namespace std;class MyClass
{
public:MyClass() { cout << "MyClass constructed!" << endl; }~MyClass() { cout << "MyClass destructed!" << endl; }
};int main()
{// 建立堆对象MyClass* ptr = new MyClass();// 使用堆对象cout << "Using heap object..." << endl;// 删除堆对象delete ptr;return 0;
}
#include <iostream>
using namespace std;class MyClass
{
public:MyClass() { cout << "MyClass constructed!" << endl; }~MyClass() { cout << "MyClass destructed!" << endl; }
};int main()
{// 建立堆对象数组MyClass* arr = new MyClass[5];// 使用堆对象数组cout << "Using heap object array..." << endl;// 删除堆对象数组delete[] arr;return 0;
}

2.2、子对象

2.3、this指针

this指针是一个指向当前对象的指针,它在成员函数中使用。this指针的作用是为了区分同名的成员变量和局部变量。在成员函数中,如果有一个参数与成员变量同名,那么在函数中直接使用该变量名时,编译器会默认使用参数而不是成员变量。这时可以使用this指针来明确指出要使用的是成员变量而不是参数。
另外,this指针还可以用于在一个成员函数中返回当前对象的引用。例如,可以在一个成员函数中返回*this,表示返回当前对象的引用。这在链式调用中非常常见,可以使代码更加简洁易读。

举个例子:

#include <iostream>
using namespace std;class Person {
public:int age;int getAge() {return this->age;}
};int main() {Person person1;person1.age = 18;cout << "person1's age is " << person1.getAge() << endl;Person person2;person2.age = 25;cout << "person2's age is " << person2.getAge() << endl;return 0;
}

上面等价于下面:

```cpp
#include <iostream>
using namespace std;class Person {
public:int age;int getAge() {return age;}
};int main() {Person person1;person1.age = 18;cout << "person1's age is " << person1.getAge() << endl;Person person2;person2.age = 25;cout << "person2's age is " << person2.getAge() << endl;return 0;
}

在成员函数中,可以直接访问类的成员变量,不需要使用"this"指针。因此,"return this->age"和"return age"是等价的。不过,使用"this"指针可以明确地表示当前对象,增加代码的可读性。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

自然语言处理

1. 自然语言处理任务 1.1. 语言的特点 词汇量大、特征多、类别多&#xff1b;语义信息丰富且隐晦&#xff0c;同义词、近义词、反语等&#xff1b;语言之间有差异性。 1.2. 自然语言处理 vs 语音识别 语音识别是把声学信号和文字进行相互转换&#xff1b;自然语言处理更多…

高性能内存池设计【传统内存管理的弊端以及解决方法】

文章目录 &#x1f34e;常用的内存操作函数&#x1f382;传统内存管理的弊端⭐弊端一⭐弊端二⭐弊端三⭐弊端四 &#x1f680;解决方法⭐内存管理工具选择⭐内存池技术 &#x1f34e;常用的内存操作函数 void *malloc(size_t size);void *calloc(size_t nmemb, size_t size);v…

paper文献和科研小工具

一、好用的网站 Aminer 二、好用的工具 ​1. SciSpace SciSpace官网 【ChatGPT 论文阅读神器】SciSpace 用户注册与实战测试 SciSpace是一款基于 ChatGPT 的论文阅读神器。 2. ReadPaper 强大且超实用的论文阅读工具——ReadPaper ReadPaper官网 ReadPaper下载链接 Rea…

重磅插件 - Bito – GPT-4

文章目录 1.介绍 Bito – GPT-42.Bito AI 功能一览2.1 AI Chat2.2 常用快捷方式2.3 生成的代码可直接插入光标处2.4 优化后的代码与源代码鲜明对比2.5 定制自己的提示模板2.6 Bito 插件2.7 Bito CLI 3.安装 Bito – GPT-44.登陆 Bito – GPT-4 创作不易&#xff0c;如果本文对你…

NBA30只球队2020年各队数据分析

今天周末有点时间&#xff0c;自己也是非常热爱篮球&#xff0c;非常喜欢勒布朗.詹姆斯和德维恩.韦德。我们对2020年NBA各队数据做一个整体分析&#xff0c;之前获取的数据在去掉一些重复数据和问题数据之后&#xff0c;数据量有所降低&#xff0c;所以此次分析纯属娱乐&#x…

哪个NBA球队会夺冠?用深度学习预测最有潜力的球员!

全文共4623字&#xff0c;预计学习时长9分钟 通过利用机器学习和人工智能的最新进展&#xff0c;一批来自加州大学伯克利分校的顶尖专家解答了一个存在已久的问题&#xff1a;如何预测哪位球员能带领球队获得NBA总冠军&#xff1f; 以下是用于做出这些预测的神经网络图&#xf…

Python:NBA球员得分数据排行爬虫

第1步&#xff1a;从网络上获取球员数据排行网页内容&#xff08;数据来源于虎扑&#xff09; 第2步&#xff1a;提取网页内容中信息到合适的数据结构 第3步&#xff1a;输出结果 代码如下&#xff1a; import requests from bs4 import BeautifulSoup import bs4 def getH…

数据分析---2.数据分析----分析NBA中国官方网站2017-2018赛季的球员数据

衣带渐宽终不悔&#xff0c;为伊消得人憔悴 上一篇文章说道了 爬取了NBA中国官方网站2017-2018赛季的球员数据保存了数据库和csv文件,今天要开始处理这些数据了。 先来看看数据内容&#xff0c;如下 """ author: cht time: 2019/9/7 12:33 """#…

巴西队提前出线,预定大力神杯?数据分析告诉你,到底谁才是冠军

2022年卡塔尔世界杯的第一轮小组赛&#xff0c;已经在众多惊诧、悲伤、惊喜的情绪中结束&#xff0c;而仅仅是第一轮的小组比赛&#xff0c;不断爆出的冷门就足以使人大跌眼镜了&#xff1a; 连续34场世界大赛不败的潘帕斯雄鹰——阿根廷&#xff0c;1-2负于世界排名51的沙特&…

用Python分析NBA球员技术

背景 12011年12月27日&#xff0c;尼克斯用一份无保障合同签下林书豪&#xff0c;23场比赛中&#xff0c;他总共只出场55分钟。2豪哥在采访中说到&#xff0c;“你找我来连练习场都不让上&#xff0c;更不用说正式比赛了”3母亲祷告&#xff1a;“God, if this is your will fo…

(更新中)篮球相关英语积累与2020年NBA东部决赛:迈阿密热火与波士顿凯尔特人

写在前面&#xff1a;一方面学习英文&#xff0c;很少刻意去积累篮球相关的英文表达&#xff1b;另一方面&#xff0c;现在记录的时刻&#xff0c;五年后、十年后回头看&#xff0c;终究是美丽的回忆。放在这里&#xff0c;也是一种青春的记录。 毕竟 Lebron James 也将在不久…

武汉光迅科技22校招笔试题(武汉邮科院控股国企上市大厂Python的txt文本处理笔试题)

武汉光迅科技22校招笔试题&#xff08;武汉邮科院控股国企上市大厂Python的txt文本处理笔试题&#xff09; 资源&#xff1a; https://download.csdn.net/download/weixin_53403301/33844279 题目要求&#xff1a; 输入数据&#xff1a; 见附件 <125模块温度查询数据.txt&…

广和通联合中国联通、紫光展锐正式发布LTE Cat.1 bis模组雁飞VN200

2023世界移动通信大会&#xff08;MWC Barcelona 2023&#xff09;于2月27日拉开帷幕&#xff0c;运营商、终端厂商、芯片商、标准组等逾千个单位参加并展示创新科技成果。期间&#xff0c;中国联通、紫光展锐与广和通联合发布LTE Cat 1 bis模组雁飞VN200。联通华盛副总经理陈丰…

未来光通信迈入多通道集成时代,泰克助力上海交大搭建下一代光通信研发平台

泰克科技 基于长期的合作与研究&#xff0c;泰克协助上海交大“区域光纤通信网与新型光通信系统”国家重点实验室&#xff08;以下简称光纤国重&#xff09;搭建起一套业界领先的光通信测试平台&#xff0c;该平台基于泰克4通道同步的59GHz高速实时示波器&#xff0c;最高支持…

致态TiPlus5000固件+升级软件(联芸MAP1202主控)

致态TiPlus5000固件进行了优化&#xff0c;从SVN7151、ZTA08322更新到ZTA09139&#xff0c;版本更新的说明如下&#xff1a;本次为硬盘兼容性更新&#xff0c;修复平台兼容性问题&#xff0c;提高固态硬盘运行稳定性。修复S.M.A.R.T信息中传感器数量及数值显示异常问题。 1、安…

2021年中国集成电路重点企业对比(光迅科技VS大唐电信VS士兰微VS中芯国际)[图]

一、现状 据国家统计局数据显示&#xff0c;2020年中国集成电路累计产量达到了2614.2亿块&#xff0c;同比增长29.53%。2021年中国集成电路累计产量达到了3594亿块&#xff0c;同比增长37.48%。 2011-2021年中国集成电路产量及增速 资料来源&#xff1a;国家统计局、智研咨询整…

光通信的最新技术趋势

大家好&#xff0c;我是小枣君。 上周&#xff0c;我参加了“2021中国光通信高质量发展论坛”&#xff0c;有一些收获与思考。特此撰文&#xff0c;与大家分享。 ▉ 光通信的发展现状 1966年&#xff0c;华裔科学家高锟博士发表了那篇划时代的经典论文——《光频率介质纤维表面…

省时科技ChatGPT服务正式发布,接入OpenAI、微软官方商用服务权限,等你来体验(文末有福利!)...

省时查报告-专业、及时、全面的报告库 省时查方案-专业、及时、全面的方案库 废话不说&#xff0c;先上ChatGPT的使用链接&#xff0c;点开就可以直接使用&#xff1a; https://chatgpt.zntjxt.com ChatGPT可以做的事情&#xff0c;相信使用过的用户有所体会&#xff0c;没用过…

可见光通信!触摸6G科技,玩转光联万物

VLC功能护眼台灯 在健康护眼台灯基础上&#xff0c;多了可见光通信功能 有什么用&#xff1f; 可见光通信&#xff1a;把信息编辑到灯光里&#xff0c;以光线的形式发散出来&#xff0c;人眼捕捉不到&#xff0c;但手机能完全接收。 有了VLC功能&#xff0c;台灯不仅是灯&…

AI将产生创富的第5次浪潮

过去30年中国改革开放&#xff0c;中国先后经历了4次创富浪潮。 第一次是在80年代&#xff0c;那时国内物资匮乏&#xff0c;人民生活水平普遍不高&#xff0c;国营经济刚刚放开&#xff0c;这时很多人选择”下海“&#xff0c;开工厂、做批发。这波人抓住了第一波创富的浪潮。…