2026《数据结构》考研复习笔记二(C++面向对象)
C++面向对象
- 一、类
- 二、继承
- 三、重载运算符和重载函数
- 四、多态
- 代码示例
一、类
1.1类&对象
class classname//class是关键词,classname是类名
{
Access specifiers://访问修饰符:private/public/protected
Date members/variables;//变量
Member functions(){}//方法
};//分号结束一个类
【例】定义Box类
class Box//盒子 private:
double length;//长
double breadth;//宽
double height;//高 //成员函数声明
public:
tuple< double,double,double>GetMessage();//获取盒子信息
void set(double len,double bre,double hei);//修改盒子信息
}
}; tuple< double,double,double> Box::GetMessage(){
return {length,breadth,height};
} void Box::set(double len,double bre,double hei){
length=len;
breadth=bre;
height=hei;
} 访问类的成员函数:
Box Box1;
Box1.GetMessage();//此处有省略,应当有构造函数,下面介绍
1.2类成员函数
成员函数的作用:
类的成员函数只属于该类,是类的一个成员,它可以访问类的成员,对具体的对象进行操作(private修饰的成员变量只能由成员函数进行修改)
成员函数的定义:
成员函数可以定义在类定义内部,或单独使用范围解析运算符::定义
如:
tuple< double,double,double> Box::GetMessage(){
return {length,breadth,height};
1.3类访问修饰符
public成员:在类的外部可以访问,不需要通过成员函数设置和获取共有变量的值
private成员:在类的外部不可访问,只有该类和友元函数可以访问私有成员
protected成员:与private成员相似,但是protected成员可以在派生类(子类)中访问
三种继承方式:
public继承:基类public成员、protected成员、private成员的访问属性在派生类中分别变成了public,protected,private
protected继承:基类public成员、protected成员、private成员的访问属性在派生类中分别变成了protected,protected,private
private继承:基类public成员、protected成员、private成员的访问属性在派生类中分别变成了private,private,private
1.4构造函数&析构函数
#include< iostream>
using namespace std; class Line
{
public:
void setLength(double len);
double getLength(void);
Line();//不带参数的构造函数
Line(double len);//带参数的构造函数
~Line();//析构函数 private:
double length;
}; Line::Line(void){
cout<<"Object is being create"<< endl;
} Line::Line(double len){
cout<<"Object is being create,length= "<< len<< endl;
} Line::~Line(void){
cout<<"Object is being deleted"<< endl;
} void Line::setLength(double len){
length=len;
} double Line::getLength(void){
return length;
} int main(){
Line line;
line.setLength(6.0);
cout<<"Length of line : "<< line.getLength()<< endl;
return 0;
} //编译上述代码并执行产生下面结果:
//Object is being created
//Length of line : 6
//Object is being deleted
1.5拷贝构造函数
拷贝构造函数属于构造函数,如果类带有指针变量并有动态内存分配,它在创建对象时,使用同一类中之前创建的对象来初始化新创建的对象。通常用于:
- 同一个同类型的对象初始化新对象(=赋值)
- 复制对象把它作为参数传递给函数
- 复制对象,并从函数返回这个对象
常见形式:
classname (const classname &obj){……}//obj是一个对象的引用,用于初始化另一个对象
【例】拷贝构造函数——此处省略class的其他函数,只展示拷贝构造函数的定义以及用法
Line::Line(const Line &obj)
{cout << "调用拷贝构造函数并为指针 ptr 分配内存" << endl;ptr = new int;*ptr = *obj.ptr; // 拷贝值
}
// 程序的主函数
int main( )
{Line line(10);Line line2=line1;print(line);return 0;
}
1.6友元函数
类的友元函数在类的定义中声明,但不是成员函数。友元函数定义在类外部,有权访问类的所有private成员和protected成员。
友元可以是函数(友元函数),也可以是类(友元类)
如:
friend void printWidth(Box box);
friend class ClassTwo;
【例】友元函数
class Box
{double width;
public:friend void printWidth( Box box );void setWidth( double wid );
};
// 请注意:printWidth() 不是任何类的成员函数
void printWidth( Box box )
{/* 因为 printWidth() 是 Box 的友元,它可以直接访问该类的任何成员 */cout << "Width of box : " << box.width <<endl;
}
printWidth( box );
1.7内联函数
函数名前有关键字inline的函数为内联函数,内联函数在编译时,编辑器会把该函数的代码副本放置在每个调用该函数的地方。类定义中定义的函数都是内联函数
1.8this指针
this是一个隐藏的指针,可以在类的成员函数中使用,用来指向当前调用对象(当一个对象的成员函数被调用时,编辑器会隐式地传递该对象的地址作为this指针)。友元函数没有this指针,因为友元不是类的成员,只有成员函数才有this指针
例如:
int compare(Box box){return this->Volume() > box.Volume();}Box1.compare(Box2);
1.9指向类的指针
一个指向 C++ 类的指针与指向结构的指针类似,访问指向类的指针的成员,需要使用成员访问运算符 ->
常见操作:
1. MyClass obj;MyClass *ptr=&obj;//指向对象
2. MyClass *ptr=new MyClass;//动态分配
3. void processObject(MyClass *ptr){ptr->display():}//作为函数参数传递
1.10类的静态对象
使用static关键字把类成员定义为静态时,无论创建多少个类的对象,静态成员变量只有一个副本(静态成员在类的所有对象中是共享的)。不能把静态成员变量的初始化放置在类的定义中,但是可以在类的外部通过使用范围解析运算符::重新声明静态变量从而对它进行初始化
静态成员函数即使在类对象不存在的情况下也能被调用,静态函数只要使用类名加范围解析运算符 :: 就可以访问。
静态成员函数没有this指针,只能访问静态成员(包含静态成员变量和静态成员函数)。静态函数即使在类对象不存在的情况下也能被调用,只要使用classname::即可访问
练习实例——点击跳转(笔者本人应用知识点写的代码)
二、继承
2.1派生类
基本形式:class derived_class:access_specifier base_class。其中derived_class是派生类名,access_specifier 是public\protected\private中的一个,base_class是基类名。例如:class Dog:public Animal{};
// 基类
class Shape { protected: int width; int height;
}; // 派生类
class Rectangle: public Shape { public: int getArea() { return (width * height); }
};
派生类可以访问基类中所有的非私有成员。因此基类成员如果不想被派生类的成员函数访问,则应在基类中声明为 private。
2.2多继承
class <派生类名>:<继承方式1><基类名1>,<继承方式2><基类名2>,…{
<派生类类体>
};
如
class A: public B, public C{……};
三、重载运算符和重载函数
C++允许在同一个作用域中函数和运算符有多个定义(参数列表不同)——函数重载和运算符重载。
3.1函数重载
重载的同名函数形参必须不同(参数的个数、类型或者顺序)。如:
void print(int i) {cout << "整数为: " << i << endl;}
void print(double f) {cout << "浮点数为: " << f << endl;}
void print(char c[]) {cout << "字符串为: " << c << endl;}
3.2运算符重载
基本形式:< return > operator < op>(parameter)
点击运算符可查看重载代码
一元运算符 | 递增运算符++,递减运算符--,负号-,逻辑非! |
二元运算符 | 加+,减-,乘*,除/ |
关系运算符 | < , > , <= , >= , == |
输入/输出运算符 | << , >> |
赋值运算符 | = |
函数调用运算符 | () |
下标运算符 | [] |
类成员访问运算符 | -> |
四、多态
4.1虚函数
- 在基类声明一个虚函数(关键字为virtual)
- 派生类可以重写虚函数
- 调用虚函数时,会根据对象的实际类型决定调用哪个版本的函数
class Animal {
public:virtual void sound() { // 虚函数cout << "Animal makes a sound" << endl;}
};class Dog : public Animal {
public:void sound() override { // 重写虚函数cout << "Dog barks" << endl;}
};
4.2动态绑定
- 在运行时决定函数调用的具体实现
- 需要使用指向基类的指针或引用来调用虚函数,运行时根据对象的类型决定调用哪个函数
Animal *animal = new Dog();animal->sound(); // 输出: Dog barks
4.3纯虚函数
当想要在基类中定义虚函数,但又不能对虚函数给出有意义的实现,这是会用到纯虚函数
- 一个包含纯虚函数的类被称为抽象类,不能被直接实例化
- 纯虚函数没有函数体 ,声明时使用=0
- 强制派生类提供具体的实现
class Shape {
public:virtual int area() = 0; // 纯虚函数,强制子类实现此方法
};class Rectangle : public Shape {
private:int width, height;
public:Rectangle(int w, int h) : width(w), height(h) { }int area() override { // 实现纯虚函数return width * height;}
};
4.4多态的实现机制
- 虚函数表:C++运行时使用虚函数表来实现多态,每个包含虚函数的类都有一个虚函数表,表中存储了指向类中所有虚函数的指针
本节实例处
代码示例
#include<iostream>
#include<tuple>
using namespace std;class Box {
private:int hei;int len;int bre;Box* next;static int num;
public:Box();//不带参数的构造函数Box(int hei, int len, int bre, Box* next = NULL);//带参数的构造函数Box(const Box& box);//拷贝构造函数(浅拷贝&深拷贝)~Box();//析构函数void set(int hei, int len, int bre, Box* next = NULL);tuple<int, int, int, Box*>GetMessage();int Volume();friend void print(const Box& box);
};int Box::num = 0;//初始化静态变量int main() {Box box(1, 1, 1);cout << "box的体积为" << box.Volume() << endl;print(box);return 0;
}Box::Box():hei(0),len(0),bre(0),next(NULL) {num++;cout << "Block box is being created" << endl;
}Box::Box(int hei, int len, int bre, Box* next) :hei(hei), len(len), bre(bre), next(next) {num++;cout << "A box is being created, whose hei is " << hei << " ,len is " << len << " and bre is " << bre << endl;
}Box::Box(const Box& box) {num++;hei = box.hei;len = box.len;bre = box.bre;next = new Box;*next = *box.next;cout << "A box is being created, whose hei is " << hei << " ,len is " << len << " and bre is " << bre << endl;
}Box::~Box() {cout << "A box is being deleted, whose hei is " << hei << " ,len is " << len << " and bre is " << bre << endl;
}void Box::set(int hei, int len, int bre, Box* next) {this->hei = hei;this->len = len;this->bre = bre;this->next = next;
}tuple<int, int, int, Box*> Box::GetMessage() {return { hei,len,bre ,next };
}int Box::Volume() {return hei * len * bre;
}void print(const Box& box) {cout << "This box message is :" << "height(" << box.hei << ")" << " " << "length(" << box.len << ")" << " " << "breadth(" << box.bre << ")" << endl;
}
跳转返回——继承
成员函数:ReturnType operator-() const{……}
全局函数:ReturnType operator-(const ClassType&obj){……}
class Counter {
private:int count;
public:Counter(int c = 0) : count(c) {}// 前置递增 ++objCounter& operator++() {++count; // 先递增return *this; // 返回当前对象的引用}int getCount() const { return count; }
};int main() {Counter c(5);++c; // 调用 operator++()std::cout << c.getCount(); // 输出 6
}
前置递增++obj重载(全局函数)
class Counter {
private:int count;
public:Counter(int c = 0) : count(c) {}friend Counter& operator++(Counter& c); // 声明友元int getCount() const { return count; }
};// 全局前置 ++
Counter& operator++(Counter& c) {++c.count;return c;
}
后置递增obj++重载(成员函数)
class Counter {
private:int count;
public:Counter(int c = 0) : count(c) {}// 后置递增 obj++Counter operator++(int) {//int是占位参数,用于区分前置和后置Counter temp = *this; // 保存当前值++count; // 递增return temp; // 返回旧值}int getCount() const { return count; }
};int main() {Counter c(5);Counter old = c++; // 调用 operator++(int)std::cout << old.getCount(); // 输出 5(旧值)std::cout << c.getCount(); // 输出 6(新值)
}
后置递增obj++重载(全局函数)
class Counter {
private:int count;
public:Counter(int c = 0) : count(c) {}friend Counter operator++(Counter& c, int); // 声明友元int getCount() const { return count; }
};// 全局后置 ++
Counter operator++(Counter& c, int) {Counter temp = c;++c.count;return temp;
}
class Number {
private:int value;
public:Number(int v) : value(v) {}// 一元减运算符重载(成员函数)Number operator-() const {return Number(-value);}int getValue() const { return value; }
};int main() {Number n(5);Number neg = -n; // 调用重载的一元减运算符std::cout << neg.getValue(); // 输出 -5
}
全局函数重载:
class Number {
private:int value;
public:Number(int v) : value(v) {}int getValue() const { return value; }
};// 一元减运算符重载(非成员函数)
Number operator-(const Number& num) {return Number(-num.getValue());
}int main() {Number n(10);Number neg = -n; // 调用重载的一元减运算符std::cout << neg.getValue(); // 输出 -10
}
class Box {
private:int hei, len, bre;
public:// ...(其他成员函数和构造函数)// 成员函数重载 +Box operator+(const Box& other) const {return Box(hei + other.hei, // 高度相加len + other.len, // 长度相加bre + other.bre // 宽度相加);}
};
全局函数重载
class Box {
private:int hei, len, bre;
public:// ...(构造函数和其他成员函数)// 声明友元,让全局函数能访问私有成员friend Box operator+(const Box& lhs, const Box& rhs);
};// 全局函数重载 +
Box operator+(const Box& lhs, const Box& rhs) {return Box(lhs.hei + rhs.hei,lhs.len + rhs.len,lhs.bre + rhs.bre);
}
class Box {
private:int hei, len, bre;
public:// ...(其他成员函数和构造函数)// 成员函数重载 ==bool operator==(const Box& other) const {return (hei == other.hei) && (len == other.len) && (bre == other.bre);}
};
全局函数
class Box {
private:int hei, len, bre;
public:// ...(构造函数和其他成员函数)// 声明友元,让全局函数能访问私有成员friend bool operator==(const Box& lhs, const Box& rhs);
};// 全局函数重载 ==
bool operator==(const Box& lhs, const Box& rhs) {return (lhs.hei == rhs.hei) && (lhs.len == rhs.len) && (lhs.bre == rhs.bre);
}
#include <iostream>
using namespace std;class Box {
private:int hei, len, bre;
public:// 声明友元函数,允许访问私有成员friend istream& operator>>(istream& is, Box& box);
};// 全局函数重载 >>
istream& operator>>(istream& is, Box& box) {is >> box.hei >> box.len >> box.bre; // 按顺序读取长、宽、高return is; // 返回输入流以支持链式调用(如 cin >> box1 >> box2)
}
class Box {
private:int hei, len, bre;Box* next; // 假设包含动态分配的资源
public:// ...(其他成员函数和构造函数)// 重载赋值运算符 =Box& operator=(const Box& other) {if (this != &other) { // 防止自赋值(如 a = a)hei = other.hei;len = other.len;bre = other.bre;// 深拷贝 next(如果存在)if (next != nullptr) {delete next; // 释放原有资源next = nullptr;}if (other.next != nullptr) {next = new Box(*other.next); // 深拷贝}}return *this; // 返回当前对象的引用}
};
#include <iostream>
using namespace std;class Adder {int value;
public:Adder(int v) : value(v) {}// 重载函数调用运算符int operator()(int x) {return value + x;}
};int main() {Adder add5(5); // 创建一个Adder对象,初始值为5cout << add5(10) << endl; // 像函数一样调用,输出15cout << add5(20) << endl; // 输出25return 0;
}
#include <iostream>
#include <vector>
using namespace std;class IntArray {vector<int> data;
public:IntArray(size_t size) : data(size) {}// 非常量版本,允许修改int& operator[](size_t index) {if (index >= data.size()) {throw out_of_range("Index out of range");}return data[index];}// 常量版本,只读访问const int& operator[](size_t index) const {if (index >= data.size()) {throw out_of_range("Index out of range");}return data[index];}size_t size() const { return data.size(); }
};int main() {IntArray arr(5);// 使用[]赋值for (size_t i = 0; i < arr.size(); ++i) {arr[i] = i * 10;}// 使用[]读取for (size_t i = 0; i < arr.size(); ++i) {cout << arr[i] << " ";}// 输出: 0 10 20 30 40// 常量对象使用const IntArray carr(3);cout << carr[0]; // 使用const版本return 0;
}
#include <iostream>
using namespace std;class Data {
public:int value;Data(int v) : value(v) {}void print() { cout << "Value: " << value << endl; }
};class DataPtr {Data* ptr;
public:DataPtr(Data* p) : ptr(p) {}~DataPtr() { delete ptr; }// 重载->运算符Data* operator->() { return ptr; }const Data* operator->() const { return ptr; }
};int main() {DataPtr dp(new Data(42));dp->print(); // 实际调用: dp.operator->()->print()dp->value = 100; // 访问成员变量const DataPtr cdp(new Data(200));cdp->print(); // 使用const版本return 0;
}
跳转返回——多态
#include <iostream>
using namespace std;// 基类 Shape,表示形状
class Shape {protected:int width, height; // 宽度和高度public:// 构造函数,带有默认参数Shape(int a = 0, int b = 0) : width(a), height(b) { }// 虚函数 area,用于计算面积// 使用 virtual 关键字,实现多态virtual int area() {cout << "Shape class area: " << endl;return 0;}
};// 派生类 Rectangle,表示矩形
class Rectangle : public Shape {public:// 构造函数,使用基类构造函数初始化 width 和 heightRectangle(int a = 0, int b = 0) : Shape(a, b) { }// 重写 area 函数,计算矩形面积int area() override { cout << "Rectangle class area: " << endl;return width * height;}
};// 派生类 Triangle,表示三角形
class Triangle : public Shape {public:// 构造函数,使用基类构造函数初始化 width 和 heightTriangle(int a = 0, int b = 0) : Shape(a, b) { }// 重写 area 函数,计算三角形面积int area() override { cout << "Triangle class area: " << endl;return (width * height / 2); }
};// 主函数
int main() {Shape *shape; // 基类指针Rectangle rec(10, 7); // 矩形对象Triangle tri(10, 5); // 三角形对象// 将基类指针指向矩形对象,并调用 area 函数shape = &rec;cout << "Rectangle Area: " << shape->area() << endl;// 将基类指针指向三角形对象,并调用 area 函数shape = &tri;cout << "Triangle Area: " << shape->area() << endl;return 0;
}