此块会再加上文件流的知识
基础知识补充:向量
一、向量
1.基础知识
在C++中,std::vector
是一种序列容器,属于标准模板库(STL)的一部分。它提供动态大小的数组功能,可以存储任何类型的元素,并允许在末尾高效地添加或删除元素。
特点:
- 可以自动调整大小以容纳更多元素。
- 支持随机访问,即可以直接通过索引访问元素。
基本操作:
push_back()
: 在向量末尾添加一个元素。pop_back()
: 删除向量末尾的元素。size()
: 返回向量中的元素数量。at()
: 安全访问特定索引的元素,带边界检查。operator[]
: 通过索引访问元素,不带边界检查。clear()
: 移除向量中的所有元素。reserve()
: 预留足够的空间以容纳指定数量的元素。
//省略前面代码
vector<int> min1;//创造一个int类型的向量
int* px = min1.data(); // 获取指向vector数据的指针
int* py = px + min1.size(); // 获取指向vector末尾的指针
for(int*p=px; p!=py;++p) {
cout << *p << " "; // 通过解引用指针来输出当前元素
// 递增指针
}
cout << endl;
2.结构体和矢量结合使用
#include <iostream>
#include <vector>
#include <string> // 包含字符串类型的头文件
// 定义一个简单的结构体 Person
struct Person {
std::string name; // 人的名字
int age; // 人的年龄
// 常规构造函数,分别设置成员变量的初始值
Person(std::string name, int age) {
this->name = name;
this->age = age;
}
};
int main() {
// 创建一个存储 Person 实例的向量
std::vector<Person> people;
// 使用构造函数创建 Person 实例并添加到向量中
people.push_back(Person("Alice", 30));
people.push_back(Person("Bob", 24));
people.push_back(Person("Charlie", 35));
// 遍历向量并打印每个 Person 的信息
for (const Person& person : people) {
std::cout << "Name: " << person.name << ", Age: " << person.age << std::endl;
}
return 0;
}
二、类和对象
类是创建对象的基础,它包含了数据成员(成员变量)和成员函数(方法),但不包含具体的数据。对象就是根据类创建的一个实例。
class Car {
public:
std::string color; // 成员变量
void start() { // 成员函数
std::cout << "The car is starting." << std::endl;
}
};
int main() {
Car myCar; // 实例化 Car 类,创建了一个 Car 类型的对象 myCar
myCar.color = "Red"; // 设置 myCar 的成员变量 color
myCar.start(); // 调用 myCar 的成员函数 start
return 0;
}
1.基础结构
- 定义一个类:就需要定义它的属性和它的行为,我们常常称之为成员变量和成员函数。
- 一定不要忘记写分号
- 公有部分and私有部分(不可外部访问,即不可被修改)
class A {
// 访问修饰控制符
public:
// 成员变量
int x;
int y;
// 成员函数
int add() {
return x + y;
}
private:
int z;
}
2.struct和class
类 = 结构体 + 成员函数
,事实上 C++ 也支持再结构体中定义少量的方法
我们通常根据使用的场景来选择使用结构体还是使用类
- 结构体:主要用来记录数据,行为极少
- 类:既有属性也有行为
在C++中 struct和class唯一的区别就在于 默认的访问权限不同
区别:
- struct 默认权限为公共
- class 默认权限为私有
3.构造函数和成员函数
构造函数是特殊的成员函数,他无需调用程序会自动执行
-
构造函数的特点:
- 构造函数的名称必须与类名完全相同,包括大小写。
- 构造函数没有返回类型,甚至没有
void
。 - 构造函数的主要目的是在创建对象时初始化对象。
- 一个类可以有多个构造函数,这是通过构造函数重载实现的(即具有不同的参数列表)。
-
成员函数的特点:
- 成员函数的名称不必与类名相同。
- 成员函数可以有返回类型,可以是任意有效的C++类型,包括
void
。 - 成员函数定义了对象的行为,可以访问和修改对象的状态。
- 除了构造函数和析构函数,类的其他成员函数都是普通成员函数。
class MyClass {
public:
// 构造函数的声明
MyClass();
MyClass(int value);
// 成员函数的声明
void doSomething();
};
// 正确的构造函数的定义,使用作用域解析运算符 ::
MyClass::MyClass() {
// 默认构造函数的实现
}
MyClass::MyClass(int value) {
// 带参数的构造函数的实现
}
// 成员函数的定义
void MyClass::doSomething() {
// doSomething 函数的实现
}
4.构造函数和析构函数
构造函数和析构函数是两种特殊的成员函数。
- 构造函数:主要作用在于创建对象时为对象的成员属性赋值,构造函数由编译器自动调用,无须手动调用。对象实例化的时候,再分配的空间上构造对象如初始化成员变量,分配资源等等
- 在C++中,析构函数是一个与对象的生命周期相关联的特殊成员函数。当一个对象的生命周期结束时,析构函数会被自动调用,以执行清理工作。通俗来讲,析构函数就像是一个“打扫房间”的过程,当一个“派对”(对象的生命周期)结束时,析构函数确保所有的“垃圾”(资源)被清理掉,房间恢复到使用前的状态。
class MyClass {
public:
MyClass() {
std::cout << "MyClass constructor called." << std::endl;
}
~MyClass() {
std::cout << "MyClass destructor called." << std::endl;
}
};
int main() {
{
MyClass localObject; // 调用构造函数
// ...
} // localObject 作用域结束,调用析构函数
MyClass* pointer = new MyClass; // 动态分配对象并调用构造函数
// ...
delete pointer; // 删除对象,先调用析构函数,然后释放内存
return 0;
}
在这个示例中,
MyClass
有一个构造函数和一个析构函数。当创建MyClass
对象时,无论是局部对象还是动态分配的对象,构造函数都会被调用。当对象的生命周期结束时,析构函数会被自动调用。对于局部对象localObject
,当它的作用域结束时,析构函数被调用。对于动态分配的对象,当使用delete
时,先调用析构函数,然后释放内存。
5.静态成员
静态成员是类的一个特性,它属于类本身,而不是类的任何特定实例(对象)。这意味着静态成员在所有对象中是共享的,每个类只有一个这样的成员。以下是静态成员的一些关键特点:
-
共享性:静态成员变量被类的所有实例共享。修改静态成员会影响到所有访问该成员的实例。
-
类作用域:静态成员的定义和声明在类的作用域内,但它们不属于任何特定的对象实例。
-
访问:可以通过类名直接访问静态成员,也可以通过对象实例访问。
-
构造函数和析构函数:静态成员没有构造函数或析构函数,它们在程序启动时初始化,并在程序结束时销毁。
静态成员就是在成员变量和成员函数前加上关键字static
class MyClass {
public:
// 静态成员变量
static int staticVar;
// 静态成员函数
static void staticFunction() {
// 可以访问静态成员变量
std::cout << "staticVar: " << staticVar << std::endl;
}
};
// 静态成员变量的初始化
int MyClass::staticVar = 0;
int main() {
// 直接通过类名访问静态成员变量和函数
MyClass::staticVar = 10;
MyClass::staticFunction(); // 输出 "staticVar: 10"
// 也可以通过对象实例访问静态成员
MyClass obj;
obj.staticVar = 20;
obj.staticFunction(); // 输出 "staticVar: 20"
return 0;
}
6.类成员初始化
初始化列表(书上似乎写的不全)
class Person {
public:
传统方式初始化
//Person(int a, int b, int c) {
// m_A = a;
// m_B = b;
// m_C = c;
//}
//初始化列表方式初始化
Person(int a, int b, int c) :m_A(a), m_B(b), m_C(c) {}
void PrintPerson() {
cout << "mA:" << m_A << endl;
cout << "mB:" << m_B << endl;
cout << "mC:" << m_C << endl;
}
private:
int m_A;
int m_B;
int m_C;
};
int main() {
Person p(1, 2, 3);
p.PrintPerson();
system("pause");
return 0;
}
7.类对象作为类成员
C++类中的成员可以是另一个类的对象,我们称该成员为 对象成员
class A {}
class B
{
A a;
}
- B类中有对象A作为成员,A为对象成员
- 那么当创建B对象时,A与B的构造和析构的顺序是谁先谁后?
- 先调用对象成员的构造,再调用本类构造(如上例中,先调用A的构造函数)
- 析构顺序与构造相反
7.继承
继承的好处:可以减少重复的代码
继承的语法:class 子类 : 继承方式 父类
class A : public B;
A 类称为子类 或 派生类
B 类称为父类 或 基类
继承方式
继承方式一共有三种:
- 公共继承
- 保护继承
- 私有继承
总之就是,如果想要继承父类中private中的东西,就把private改成protected,这样就可以继承protected内的方法
三、文件
C++中对文件操作需要包含头文件#include < fstream >
文件类型分为两种:
文本文件 - 文件以文本的ASCII码形式存储在计算机中
二进制文件 - 文件以文本的二进制形式存储在计算机中,用户一般不能直接读懂它们
操作文件的三大类:
ofstream:写操作
ifstream: 读操作
fstream : 读写操作
1.读取文件
-
包含头文件
#include <fstream>
-
创建流对象
ifstream ifs;
-
打开文件并判断文件是否打开成功
ifs.open(“文件路径”,打开方式);
-
读数据
-
关闭文件
ifs.close();
读取一个数据文件如下图代码
#include <iostream>
#include <fstream> // 包含文件操作的头文件
#include <string> // 包含字符串类的头文件
usingnamespace std;
int main() {
ifstream file; // 定义一个ifstream对象用于文件读取
string line; // 定义一个字符串用于存储读取的每一行
// 打开文件
file.open("example.txt", ios::in); // "example.txt" 是要读取的文件名
// 检查文件是否成功打开
if (!file.is_open()) {
cout << "Unable to open file." << endl;
return 1; // 如果文件无法打开,返回错误码
}
// 使用getline函数读取文件,直到文件末尾
while (getline(file, line)) {
// getline函数成功时返回的对象可以用于判断读取是否成功
// 每读取一行,就输出这一行
cout << line << std::endl;
}
// 关闭文件
file.close();
return 0; // 正常退出
}
四、期末往届真题
1.填空题
解答:(1)void A::
(2)w.max(a1,b1);
就是要定义成员函数和调用
答:n*fact(n-1)
答:int i = 32;
a >= "A" && a<="Z"
因为小写字母比大写字母ASCII码大32
2.程序分析题
分析:主函数中用了exchange函数,故会判断a,b,c的大小,可以知道a<b,所以执行func(a,b),也就是a和b会交换数值;此时a=89,b=12,故继续运行func(b,c),最后结果是a=89,b=56,c=12
分析:调用了my1中的set函数,所以number = 5,第一个输出5;第二个对number进行赋值,number是主函数中的变量,也就是10,所以输出10;最后一步输出3
这道题:
::number
明确指出我们想要访问的是全局变量number
。
分析:在主函数中,创造了一个名为a的对象,构造函数(11,12),表示a1=11,a2=12,调用print函数,故输出(11,12);接着创建一个类B,名为b的实例,构造函数运行,a1=31,a2=32,b1=33,b2=34;调用fun()函数,调用move(5,8)函数,a1=a1+5,a2=a2+8,第哦啊用print函数,故输出(33,34);接着调用f()函数,输出父类A中的print函数,也就是(36,40)
3.改错题
1.要改为 p=&i,因为指针要一个地址值,&是解地址符
2.漏了using namespace std;
4.程序设计题
我用的递归函数 你们可以自己想数学逻辑的写法
#include <iostream>
using namespace std;
//这道题重在理解题目意思
int count(int n){
if(n==1){
return 1;
}
else if(n==2){
return 2;
}
else if(n==3){
return 3;
}
else{
return count(n-1)+count(n-3);
}
}
int main() {
int y; // 年份 ,学校人数
cin>>y;
cout<<count(y);
return 0;
}
第二题建议自己写一遍再来看我的
要注意访问私有数据成员就必须在公有的成员函数里访问!
要有两个构造函数
实例化:R1 = Rectangle(al, a2);
R2 = Rectangle(b1, b2);或者我写的这种都可以
我调了很久bug
要注意一下 构造函数是没有类型的 成员函数必须有类型!!
类外定义要记得用::
#include<iostream>
using namespace std;
class Rectangle{
private:
double width,height;
public:
Rectangle();
Rectangle(double,double);//带参数的构造函数
double GetArea();//成员函数
};
Rectangle::Rectangle(){
width = 10;
height = 10;
}
Rectangle::Rectangle(double w,double h){
width = w;
height = h;
}
double Rectangle::GetArea(){
return width*height;
}
int main(){
double a1,a2,b1,b2;
cin>>a1>>a2>>b1>>b2;
Rectangle R1(a1,a2);
Rectangle R2(b1,b2);
double s1 = R1.GetArea();
double s2 = R2.GetArea();
cout<<s1<<endl;
cout<<s2<<endl;
if (s1>s2){
cout<<"R1面积更大";}
else if (s1<s2){
cout<<"R2面积更大";}
else{
cout<<"面积相等";}
}