静态链表
struct student
{
int num;
float score;
struct student * next;
};
int main()
{
student a, b, c, * head, * p;
a.num = 31001; a.score = 89.5;
b.num = 31003; b.score = 90;
c.num = 31007; c.score = 85;
head = &a;
a.next = &b;
b.next = &c;
c.next = NULL;
p = head;
do
{
cout << p->num << " " << p->score << endl;
p = p->next;
} while (p != NULL);
return 0;
}
通过p和当前结构体中的next来进行访问
动态链表
创建动态链表最主要是注意结构体变量中的指针的指向。并且掌握如何创建结构体节点。首先创建一个 :结构体名称 * p=new 结构体名称(意思是开辟一段储存头指针是p的一段动态空间)然后注意p和p->next都代表的是地址(p代表的是该节点的首地址;p->next代表的是该节点指向下一节点的地址)
//创建动态链表
#include<iostream>
#include<string>
using namespace std;
//创建结构体
struct student
{
int num;
string name;
struct student* next=NULL;
};
//函数的声明
student * creat_list( int n);
void print_list(student* head);
void insert(student* head, int stu_num);//在链表中间追加
student * addhead(student* head);
void change_list(student* head);
int main()
{
//根据用户指定的数量创建指定数量个节点的动态链表
cout << " 请输入学生的数量" << endl;
int n = 0;
cin >> n;
student * head=creat_list(n);
/*
//链表的中间追加
int stu_num = 0;
cout << "请输入要增加到第几个节点之后" << endl;
cin >> stu_num;
insert(head, stu_num);
//链表的头部追加
//addhead(head);
*/
//head=addhead(head);
change_list(head);
//打印链表
print_list(head);
return 0;
}
//函数的实现
student * creat_list(int n)
{
student* head = new student;//头指针无需使用循环创建,必须存在
/*
这里实际运用new student创建了一个学生节点
另head指向了整个链表中的第一个节点
此时头结点并没有具体的名称
*/
student * p = head;//表示当前的指针和目前指向的节点是谁
for (int i = 0; i < n; i++)
{//根据n的大小来创建如干个节点
student* node = new student;//node表示新创建的节点
cout << "请输入学生的编号" << endl;
cin >> node->num;
cout << "请输入学生的姓名" << endl;
cin >> node->name;
//还需建立和之前的链表的关联
p->next =node;//零当前的头指针指向第一个借点
p = p->next;
}
//注意此时最好返回头指针
return head->next;
}
void print_list(student* head)
{//从头结点开始
student* p = head;//将链表的头结点赋值到p
while (p!= NULL)
{
cout << "这是第" << p->num << "个学生" <<p->name<< endl;
p = p->next;//将指针移动到下一个节点的地址处
}
cout << "链表输出完成" << endl;
}
void insert(student* head, int stu_num)
{
student* temp;
int num = stu_num;
student* p = head;
for (int i = 0; i < num -1; i++)
{
//找出指向该节点的指针
p = p->next;
}
//创建新的节点
student* newnode = new student;//node表示新创建的节点
cout << "请输入学生的编号" << endl;
cin >> newnode->num;
cout << "请输入学生的姓名" << endl;
cin >> newnode->name;
//记录该节点之前指向的指针的位置
temp = p->next;
//将该节点指向新的指针
p->next = newnode;
//将新的指针指向该节点原来后面节点的位置
newnode->next = temp;
cout << "创建成功" << endl;
}
student * addhead(student* head)
{//创建一个新的节点
student* newnode = new student;
cout << "请输入新的学生的信息学号和名字" << endl;
cin >> newnode->num;
cin >> newnode->name;
//将原本的头指针保存
student* temp = head;
//将头指针指向新的节点
head = newnode;
//将新的节点指向原本头指针所指
newnode->next = temp;
cout << "头结点添加成功" << endl;
return head;
}
void change_list(student* head)
{
student* p=head;
print_list(head);
cout << "请输入要更改的节点位置" << endl;
int num;
cin >> num;
for (int i = 0; i < num-1; i++)
{
p = p->next;
}
cout << "学生编号是" << p->num << "学生姓名是" << p->name << endl;
cout << "请重新输入这两项" << endl;
cin >> p->num;
cin >> p->name;
cout << "修改完成" << endl;
}
二进制文件的读写
无论是二进制文件的读写还是普通文件的读写都要包含《fstream》的头文件
注意在ostream outfile(“名字”,iosbinary);(有个分号)
Outfile.write((char *)&stu[i],sizeof(stu[i]));
infile.write((char *)&stu[i],sizeof(stu[i]));
一样要先创建文件ofstream outfile(“文件名”,ios::out);(如果不写后面系统会默认iOS::out方式打开)
Out<<a[i]<<” “;
输出方式:
Infile>>a[i];
#include<iostream>
#include<fstream>//文件输入输出流专有头文件
#include<iomanip>
using namespace std;
struct student
{
string name;
int num;
int age;
char sex;
};
int main()
{
//先创建一个结构体数组来储存要读出的数据
student stu[3] = {"Li",1,1,'f',"wang",2,2,'f',"fang",3,3,'m'};
int i;
ofstream outfile("student.dat", ios::binary);
/*
输出全部规定用ofstream并且是outfile
iosbinary是一个创建二进制文件并且打开的一个操作命令
*/
if (!outfile)
{
cerr << "open error!" << endl;
exit(2);
}
for (int i = 0; i < 3; i++)
{
//利用write对文件进行读入
outfile.write((char*)&stu[i], sizeof(stu[i]));
}
//注意要对打开的文件进行关闭
outfile.close();
cout << "已经完成文件的录入,接下来进行文件的读取" << endl;
/*
在文件的读取中规定使用
istream infile("文件名",打开方式);
*/
ifstream infile("student.dat", ios::binary);
if (!infile)
{
cerr << "open error!" << endl;
exit(2);
}
for (int i = 0; i < 3; i++)
{
//通过读取infile的函数read((char *)&stu[i],sizeof(stu[i]))
//里面的内容的意思是将stu[i]强制转化为char*类型并且取stu[i]的地址,后面是stu[i]的长度
infile.read((char*)&stu[i], sizeof(stu[i]));
}
for (int i = 0; i < 3; i++)
{
cout << setw(4)<< stu[i].name << " " << stu[i].num << " " << stu[i].age << " " << stu[i].sex << endl;
}
infile.close();
return 0;
}
动态数组的设置
new int [a]标记了一段长度为4*a的空间来存放数组利用int * p来标记开辟的空间的首地址。
#include<iostream>
using namespace std;
void print(int * arr,int n)
{
for (int i = 0; i <n; i++)
{
cout << arr[i] << endl;
}
}
int main()
{
int a;
cout << "请输入数组的长度" << endl;
cin >> a;
//new int [a]标记了一段长度为4*a的空间来存放数组
//利用int * p来标记开辟的空间的首地址
int * p = new int[a];
for (int i = 0; i < a; i++)
{
cout << "请输入数组中第" << i+1 << "个数" << endl;
//注意这里可以直接使用p[]
cin >> p[i];
}
print(p, a);
delete[]p;
return 0;
}
构造函数
默认构造函数 (Default Constructor)(缺省构造函数)
无需任何参数的构造函数。
如果程序员没有为类定义任何构造函数,编译器会自动生成一个默认构造函数。
默认构造函数可以被显式定义(即程序员提供了定义),也可以被隐式删除(如果类中定义了其他构造函数并且程序员想要阻止隐式生成的默认构造函数)。
带参数的构造函数 (Parameterized Constructor)
需要一个或多个参数的构造函数。
允许程序员在创建对象时提供初始化值。
(两种构造函数)
#include <iostream>
#include <string>
using namespace std;
class Person
{
public:
// 带参构造函数
Person(string name, int age) : name(name), age(age) {}
// Person(std::string n, int a)
//{
// name = n;
// age = a;
//}
//缺省构造函数
Person();
private:
string name; // 成员变量:姓名
int age; // 成员变量:年龄
};
Person::Person()
{
cin >> name;
cin >> age;
}
(构造函数的重载)
// 无参构造函数(缺省构造函数)
Person() {
std::cout << "Default constructor called." << std::endl;
name_ = "Unknown";
age_ = 0;
}
// 带两个参数的构造函数
Person(std::string name, int age) : name_(name), age_(age) {
std::cout << "Constructor with name and age called." << std::endl;
}
其实是就是将其中一个比如age(0)并且在一开始没有添加接受age的输入
// 带一个参数的构造函数(只接受名字)
Person(const std::string& name) : name_(name), age_(0) {
std::cout << "Constructor with name only called." << std::endl;
}
// 输出Person的信息
void display() const {
std::cout << "Name: " << name_ << ", Age: " << age_ << std::endl;
}
(在继承中的构造函数)
Child(int parentVal, int childVal) : Parent(parentVal), childValue(childVal) {
}
Child中没有新生成的量
虚函数和纯虚函数
派生类必须为纯虚函数提供定义
虚函数是一个完整的函数(如果是int 必须return)
虚函数不一定在子类中重新定义
virtual int foo()
{ return 0;}
纯虚函数一定要在子类中重新定义
Virtual int area() =0;
虚基类
在子类的继承的时候加上:vitrual public
作用是避免重复继承
在继承中遇到同名函数在继承中被子类宠重新定义,为了能够更加方便的调用这些同名函数(可以使用对象.类型::函数)。利用基类设置一个指针(grade * g1)指针到时候可以指向子类中的对象来调用这个类中的同名函数
将函数设置成类的友元函数可以在函数中利用引用调用类中的成员
//在类中声明
friend void show(Time&);
//在类外定义
void show(Time& t)
{
cout << t.hour << ";" << t.minute << ":" << t.second << endl;
}
一目运算符的重载
不能重载的运算符:
. (成员访问运算符)
*(成员指针访问运算符)
::(域运算符)
Sizeof(长度运算符)
?:(条件运算符)
#include<iostream>
using namespace std;
class complex
{
int real;
int imag;
public:
//引用一个c2来实现两个数相加
可以将函数变成类的友元函数不过要设置两个引用因为外界函数不能一开始就调用类中的数据成员
(优点不需要加号左边一定是类的对象)(并且不用声明是类的函数)
complex operator +(complex& c2);
complex()
{
cout << "请输入" << endl;
cin >> real;
cin >> imag;
}
void show()
{
cout << real << "." << imag << endl;
}
};
//是complex类型的函数
//是complex类中的函数
complex complex::operator+(complex& c2)
{
//设置c3来储存两个数相加
complex c3;
//是类中的函数可以直接调用类中的数据成员
c3.real = real + c2.real;
c3.imag = imag + c2.imag;
//将c3返回
return c3;
}
int main()
{
complex c1, c2, c3;
c3 = c1 + c2;
c3.show();
}
双目运算符的重载
源代码:
#include<iostream>
using namespace std;
class String
{
public:
String() { p = NULL; }
//带参构造函数
String(char* s);
friend bool operator >(String& string1, String& string2);
void display();
private:
char* p;
};
String::String(char* s) { p = s; }
bool operator >(String& string1, String& string2)
{
if (strcmp(string1.p, string2.p) > 0)
{
return true;
}
else
{
return false;
}
}
void String::display()
{
cout << p;
}
int main()
{
String s1("Hello"), s2("Bye");
cout << (s1 > s2) << endl;
}
重载流插入运算符
需要在类中将下面的函数进行友元出现:
//因为要用ostream类中的<<所以要ostream& operator
//然后括号里是两个引用
friend ostream& operator << (ostream&, Complex&);
在函数中
ostream& operator << (ostream& output, Complex& c)
{
//将想要输出的地方输送到output中直到output遇到endl或者满了
output << "(" << c.real << "+" << c.imag << ")" << endl;
//输出output
return output;
}
重载提取流运算符
Ostream变成istream
然后istream&input
通过input>>c.real>>c.imag;
然后return input;