深圳大学面向对象程序设计(OOP)期末复习
深圳大学面向对象程序设计(OOP)期末复习
所用课本是钱能的《C++程序设计教程》,2025-2026学年春季学期人工智能学院的OOP课程
第十一章 类
类的作用是封装,可以封装多种函数,使得他们不会轻易被外部修改。
一般采用这样的格式:
class Student {
private:
// 数据成员
public:
// 构造函数
// getter / setter
// 其他成员函数
};
:: 称为作用域解析运算符。
Rectangle::area 表示 area 是 Rectangle 类作用域中的成员
使用类名::函数名,可以明确函数属于哪个类
完整的类外实现
#include <iostream>
using namespace std;
class Rectangle {
private:
double width;
double height;
public:
// 构造函数声明。
Rectangle(double newWidth, double newHeight);
// 普通成员函数声明。
double area() const;
//函数后面的const表面这个成员函数不会修改当前对象
double perimeter() const;
};
// 构造函数类外实现。
Rectangle::Rectangle(double newWidth, double newHeight)
: width(newWidth), height(newHeight) {
}
// area 类外实现。
double Rectangle::area() const {
return width * height;
}
// perimeter 类外实现。
double Rectangle::perimeter() const {
return 2 * (width + height);
}
int main() {
Rectangle rect(3.0, 4.0);
cout << rect.area() << '\n';
cout << rect.perimeter() << '\n';
return 0;
}
初始化列表:成员直接被初始化为目标值,比函数体赋值更好,函数体赋值时先完成默认初始化,再被重新赋值。
Student(const string& newName,int newScore)
:name(newName),score(newScore){
}
构造函数重载
同一个类可以有多个构造函数,只要参数列表不同。
class Point {
private:
int x;
int y;
public:
// 无参构造函数。
Point()
: x(0), y(0) {
}
// 一个参数构造函数。
Point(int value)
: x(value), y(value) {
}
// 两个参数构造函数。
Point(int newX, int newY)
: x(newX), y(newY) {
}
};
使用这样的方式
Point a;
Point b(3);
Point c(3, 4);
就可以分别调用不同构造函数。
这就是构造函数重载
析构函数
在对象生命周期结束时自动调用的特殊成员函数
什么时候运行的位置离开作用域,什么时候执行析构函数。
析构函数不能写返回类型,不能带参数。
动态数组的申请与释放
class IntArray{
private:
int* data;
int size;
public:
IntArray(int n)
:size(n){
//动态申请数组
data=new int[size]
}
~IntArray(){
//释放动态数组,由于是多个对象所以是delete[]
delete[] data;
}
};
静态成员与友元
继承
在已有类的基础上定义一个新类,新类自动拥有原类中的部分成员
比如先定义公共的A类
//基类
class A{
};
再定义出派生类B和C:
//派生类
class B:public A{
};
class C:public A{
};
最简单的继承
#include<bits/stdc++.h>
using namespace std;
//定义基类Person
class Person{
public:
string name;
int age;
void displayBasicInfo() const{
cout<<name<<" "<<age;
}
};
//Student公有继承Person
class Student:public Person{
public:
int score;
void display() const{
//name和age继承person,score是student中自己定义的成员
cout<<name<<" "<<age<<" "<<score<<endl;
}
};
int main(){
Student stu;
//Student 对象可以使用继承来的成员。
stu.name="Alice";
stu.age=19;
//score 是 Student 自己新增的成员。
stu.score=95;
stu.display;
return 0;
}
使用继承就不用重复定义很多变量了。
class的默认继承方式
class Student:Person{};
这种方式默认为private继承,即:
class Student:private Person{};
所以不要忘记写public!!!!!
区分三种成员访问权限
-
private: 本类内部可以访问 派生类不能直接访问 类外不能访问
-
protected: 本类内部可以访问 派生类可以访问 类外不能访问
-
public: 本类内部可以访问 派生类可以访问 类外可以访问
多态
指向同一个接口,根据不同对象表现不同。
三个条件:
-
有继承
class Dog::public Animal -
父类条件必须virtual
class Animal{ virtual void speak(); } -
子类重写
void speak() override -
用父类指针或引用调用
Animal* p=&dog; p->speak();
多继承
一个孩子两个爸爸。
class SmartPhone
:public Camera,
public Phone
{
};
虚继承
用于解决多继承产生重复父类的问题,即菱形继承问题。
看下图中的TA,就会出现两个person,一个来自student,一个来自teacher
Person
/ \
Student Teacher
\ /
TA
解决方法:
class Student
:
virtual public Person
{
};
class Teacher
:
virtual public Person
{
};
这样TA只有一个Person
再总结一下代码模板框架:
-
普通继承
class child : public Parent{}; -
派生构造
Child() : Parent(){} -
虚函数
父类(virtual)
class Animal{ public: virtual void speak(){} };子类(override)
class Dog::public Animal { public: void speak() override { } };调用
Animal* p=new Dog; p->speak(); -
多继承
class C : public A, public B { };
运算符重载
方法1:成员函数(private变量不能访问)
返回类型 operator符号(参数)
{
}
例如
Complex operator+(Complex a,Complex b)
{
return Complex(a.real+b.real,a.imag+b.imag);
}
//调用a+b相当于a.operator+(b),左边对象隐藏传入
方法2:友元函数(private变量可以访问)
//friend 返回类型 operator符号(参数1,参数2)
class Complex
{
private:
int real;
friend Complex operator+(Complex a,Complex b);
};
IO流重载
输入
friend istream& operator>>(istream& in,ClassName& obj)
{
in>>obj.xxx;
return in;
}
输出
friend ostream& operator<<(ostream& out,ClassName& obj)
{
out<<obj.xxx;
return out;
}
来一个具体的例子
#include<bits/stdc++.h>
using namespace std;
class Complex{
private:
int real,imag;
public:
//构造函数
Complex(int real=0,int imag=0)
:real(real),imag(imag){
}
//重载加法
friend Complex operator+(Complex& a,Complex& b)
{
return Complex(a.real+b.real,a.imag+b.imag);
}
//重载输出
friend ostream& operator<<(ostream& out,Complex& a)
{
out<<a.real<<"+"<<a.imag<<"i";
return out;
}
};
int main()
{
Complex a(1,2);
Complex b(3,4);
Complex c=a+b;
cout<<c;
return 0;
}
拷贝构造函数
复制类
基础形式:
Student(Student& s){}
特点是函数名和类名一样,没有返回值,参数必须是同类型对象引用。
需要自己写拷贝构造的情况有两种:
- 普通变量没问题
- 指针变量有问题
如果普通构造一个类,那private中的两个指针会指向同一个地址,这就是浅拷贝
a.score ----\
\
--->100分
/
b.score ----/
浅拷贝是危险的,如果析构函数中 delete 这个内存,那么浅拷贝后会被delete两次,程序会崩溃。
所以我们需要深拷贝来重新申请空间
class Student{
private:
int* score;
public:
Student(int s)
{
score=new int(s);
}
Student(const Student& s)
{
score=new int(*s.score);//深拷贝
}
~Student(){
delete score;
}
};
友元
允许非成员函数访问private元素
class Metal
{
private:
int hardness;
int weight;
int volume;
public:
Metal(int h,int w,int v);
friend Metal operator+
(
const Metal& a,
const Metal& b
);
};
模板
大概长这样,嗯。
#include<bits/stdc++.h>
using namespace std;
template<class T>
T max(T arr[],int len)
{
T mx=arr[0];
for(int i=1;i<len;i++)
{
if(arr[i]>mx) mx=arr[i];
}
return mx;
}
template<class T>
class Cryption{
private:
T ptxt[100];
T ctxt[100];
T key;
int len;
public:
Cryption(T tk,T tt[],int tl);
void Encrypt();
void Print();
};
template<class T>
Cryption<T>::Cryption(T tk,T tt[],int tl)
{
key=tk;
len=tl;
for(int i=0;i<len;i++) ptxt[i]=tt[i];
}
template<class T>
void Cryption<T>::Encrypt()
{
T mx=max(ptxt,len);
for(int i=0;i<len;i++)
{
ctxt[i]=key+(mx-ptxt[i]);
}
}
template<class T>
void Cryption<T>::Print()
{
for(int i=0;i<len;i++)
{
if(i!=len-1)
cout<<ctxt[i]<<" ";
else
cout<<ctxt[i];
}
cout<<endl;
}
int main()
{
int i,length,ik,itxt[100];
double dk,dtxt[100];
char ck,ctxt[100];
cin>>ik>>length;
for(int i=0;i<length;i++) cin>>itxt[i];
Cryption<int> ic(ik,itxt,length);
ic.Encrypt();
ic.Print();
cin>>dk>>length;
for(int i=0;i<length;i++) cin>>dtxt[i];
Cryption<double> dc(dk,dtxt,length);
dc.Encrypt();
dc.Print();
cin>>ck>>length;
for(int i=0;i<length;i++) cin>>ctxt[i];
Cryption<char> cc(ck,ctxt,length);
cc.Encrypt();
cc.Print();
return 0;
}
拆解一下,一般函数模板就是能兼容多种数据类型的类。
-
类前
template<class T> class A{ private: T x,y,z; int k; }; -
类外实现成员函数
template<class T> void A<T>::fun()

浙公网安备 33010602011771号