25.面向对象-多态-抽象类
25.1 知识点
抽象类
抽象类是指包含至少一个纯虚函数的类
基本特点:
- 不能直接实例化
- 只能被继承
- 若子类继承抽象类后不实现纯虚函数,也会变成抽象类
- 抽象类中可以有成员变量和普通函数
纯虚函数
纯虚函数就是没有被实现的虚函数
语法:
virtual 返回类型 函数名(参数列表) = 0;
纯虚函数一般用来表示抽象的行为
举例说明:
- 图形基类
- / | \
- 圆 正方形 长方形
举例说明
#pragma once
#include <iostream>
using namespace std;
class Fruit
{
private:
string name;
public:
Fruit(string name)
{
this->name = name;
}
virtual ~Fruit()
{
}
//纯虚函数 因为不同的水果被吃的方式不同
virtual void Eat() = 0;
void Washing()
{
cout << "洗水果:" << name << endl;
}
};
#pragma once
#include "Fruit.h"
class Apple : public Fruit
{
public:
Apple(string name) : Fruit(name)
{
}
void Eat() override
{
cout << "直接咬苹果来吃" << endl;
}
};
#pragma once
#include "Fruit.h"
class Banana : public Fruit
{
public:
Banana(string name) : Fruit(name)
{
}
void Eat() override
{
cout << "剥开香蕉吃" << endl;
}
};
测试调用代码
Fruit* a = new Apple("苹果");
a->Washing();
a->Eat();
delete a;
a = nullptr;
Fruit* b = new Banana("香蕉");
b->Washing();
b->Eat();
delete b;
b = nullptr;
输出:
洗水果:苹果
直接咬苹果来吃
洗水果:香蕉
剥开香蕉吃
25.2 知识点代码
Fruit.cpp
#pragma once
#include <iostream>
using namespace std;
class Fruit
{
private:
string name;
public:
Fruit(string name)
{
this->name = name;
}
virtual ~Fruit()
{
}
//纯虚函数 因为不同的水果被吃的方式不同
virtual void Eat() = 0;
void Washing()
{
cout << "洗水果:" << name << endl;
}
};
Apple.cpp
#pragma once
#include "Fruit.h"
class Apple : public Fruit
{
public:
Apple(string name) : Fruit(name)
{
}
void Eat() override
{
cout << "直接咬苹果来吃" << endl;
}
};
Banana.cpp
#pragma once
#include "Fruit.h"
class Banana : public Fruit
{
public:
Banana(string name) : Fruit(name)
{
}
void Eat() override
{
cout << "剥开香蕉吃" << endl;
}
};
Lesson25_面向对象_多态_抽象类.cpp
#include <iostream>
#include "Fruit.h"
#include "Apple.h"
#include "Banana.h"
int main()
{
#pragma region 知识点一 抽象类
//概念:
//抽象类是指包含至少一个纯虚函数的类
//基本特点:
//1.不能直接实例化
//2.只能被继承
//3.若子类继承抽象类后不实现纯虚函数,也会变成抽象类
//4.抽象类中可以有成员变量和普通函数
#pragma endregion
#pragma region 知识点二 纯虚函数
//纯虚函数就是没有被实现的虚函数
//语法:
//virtual 返回类型 函数名(参数列表) = 0;
//纯虚函数一般用来表示抽象的行为
//比如:
// 图形基类
// / | \
//圆 正方形 长方形
#pragma endregion
#pragma region 知识点三 举例说明
Fruit* a = new Apple("苹果");
a->Washing();
a->Eat();
delete a;
a = nullptr;
Fruit* b = new Banana("香蕉");
b->Washing();
b->Eat();
delete b;
b = nullptr;
//洗水果:苹果
//直接咬苹果来吃
//洗水果 : 香蕉
//剥开香蕉吃
#pragma endregion
}
25.3 练习题
写一个动物抽象类,写三个子类:人叫,狗叫,猫叫
首先,我们定义一个抽象类 Animal
,其中包含一个纯虚函数 Speak()
,表示发出叫声。同时我们定义一个虚析构函数,确保子类对象通过父类指针释放时能正确析构。
#pragma once
#include <iostream>
using namespace std;
// 抽象类 Animal:定义了一个纯虚函数 Speak 表示发声
class Animal
{
public:
// 纯虚函数,所有子类必须重写该方法以实现具体发声
virtual void Speak() = 0;
// 虚析构函数,确保通过父类指针删除子类对象时资源正确释放
virtual ~Animal() {}
};
接下来创建三个继承 Animal
的子类:
人类 Person 类
#pragma once
#include "Animal.h"
class Person : public Animal
{
public:
// 实现 Speak 方法,表示人说“你好”
void Speak() override
{
cout << "你好" << endl;
}
};
狗类 Dog
#pragma once
#include "Animal.h"
class Dog : public Animal
{
public:
// 实现 Speak 方法,表示狗叫“汪汪”
void Speak() override
{
cout << "汪汪" << endl;
}
};
猫类 Cat
#pragma once
#include "Animal.h"
class Cat : public Animal
{
public:
// 实现 Speak 方法,表示猫叫“喵喵”
void Speak() override
{
cout << "喵喵" << endl;
}
};
测试代码
Animal* p = new Person();
p->Speak(); // 输出:你好
delete p;
p = nullptr;
Animal* d = new Dog();
d->Speak(); // 输出:汪汪
delete d;
d = nullptr;
Animal* c = new Cat();
c->Speak(); // 输出:喵喵
delete c;
c = nullptr;
创建一个图形类,包含求面积和周长两个方法。创建矩形类、正方形类、圆形类继承图形类,实例化对象并求面积和周长
定义一个抽象类 Graph
,包含两个纯虚函数:GetLength()
和 GetArea()
,分别表示周长和面积的计算。
#pragma once
class Graph
{
public:
// 计算图形的周长
virtual float GetLength() = 0;
// 计算图形的面积
virtual float GetArea() = 0;
virtual ~Graph() {}
};
矩形类 Rect
#pragma once
#include "Graph.h"
class Rect : public Graph
{
public:
Rect(float w, float h);
float GetLength() override;
float GetArea() override;
private:
float w, h;
};
#include "Rect.h"
Rect::Rect(float w, float h)
{
this->w = w;
this->h = h;
}
float Rect::GetLength()
{
return (w + h) * 2;
}
float Rect::GetArea()
{
return w * h;
}
正方形类 Square
#pragma once
#include "Graph.h"
class Square : public Graph
{
public:
Square(float l);
float GetLength() override;
float GetArea() override;
private:
float l;
};
#include "Square.h"
Square::Square(float l)
{
this->l = l;
}
float Square::GetLength()
{
return l * 4;
}
float Square::GetArea()
{
return l * l;
}
圆形类 Circular
#pragma once
#include "Graph.h"
class Circular : public Graph
{
public:
Circular(float r);
float GetLength() override;
float GetArea() override;
private:
float r;
};
#include "Circular.h"
Circular::Circular(float r)
{
this->r = r;
}
float Circular::GetLength()
{
// 圆周长公式:2πr
return 2 * 3.14f * r;
}
float Circular::GetArea()
{
// 圆面积公式:πr²
return 3.14f * r * r;
}
测试代码
Graph* g = new Rect(5, 6);
cout << g->GetLength() << endl; // 22
cout << g->GetArea() << endl; // 30
delete g;
g = nullptr;
g = new Square(5);
cout << g->GetLength() << endl; // 20
cout << g->GetArea() << endl; // 25
delete g;
g = nullptr;
g = new Circular(3);
cout << g->GetLength() << endl; // 18.84
cout << g->GetArea() << endl; // 28.26
delete g;
g = nullptr;
C++ 中抽象类中的纯虚函数在子类中必须被实现吗?
不一定。
需要根据具体情况来判断:
- 如果子类对象要被实例化,那么必须实现所有继承下来的纯虚函数。
- 如果子类对象不需要被实例化,子类就可以不实现纯虚函数。
这是因为:
- 若子类没有实现所有的纯虚函数,它本身也仍然是一个抽象类。抽象类不能被实例化。
- 只有当子类实现了父类的全部纯虚函数后,才能变成具体类,才能创建其实例。
总结:
- 子类是否必须实现父类中的纯虚函数,取决于是否需要实例化子类对象。
- 纯虚函数就是为继承类约定一个“必须实现的接口”,否则子类也会变成抽象类。
25.4 练习题代码
Animal.h
#pragma once
#include <iostream>
using namespace std;
class Animal
{
public:
virtual void Speak() = 0;
virtual ~Animal()
{
}
};
Person.h
#pragma once
#include "Animal.h"
class Person :
public Animal
{
public:
void Speak() override
{
cout << "你好" << endl;
}
};
Dog.h
#pragma once
#include "Animal.h"
class Dog :
public Animal
{
public:
void Speak() override
{
cout << "汪汪" << endl;
}
};
Cat.h
#pragma once
#include "Animal.h"
class Cat :
public Animal
{
public:
void Speak() override
{
cout << "喵喵" << endl;
}
};
Graph.h
#pragma once
class Graph
{
public:
virtual float GetLength() = 0;
virtual float GetArea() = 0;
};
Rect.h
#pragma once
#include "Graph.h"
class Rect :
public Graph
{
private:
float w;
float h;
public:
Rect(float w, float h);
float GetLength() override;
float GetArea() override;
};
Rect.cpp
#include "Rect.h"
Rect::Rect(float w, float h)
{
this->w = w;
this->h = h;
}
float Rect::GetLength()
{
return (w + h) * 2;
}
float Rect::GetArea()
{
return w * h;
}
Square.h
#pragma once
#include "Graph.h"
class Square :
public Graph
{
private:
float l;
public:
Square(float l);
float GetLength() override;
float GetArea() override;
};
Square.cpp
#include "Square.h"
Square::Square(float l)
{
this->l = l;
}
float Square::GetLength()
{
return l * 4;
}
float Square::GetArea()
{
return l * l;
}
Circular.h
#pragma once
#include "Graph.h"
class Circular :
public Graph
{
private:
float r;
public:
Circular(float r);
float GetLength() override;
float GetArea() override;
};
Circular.cpp
#include "Circular.h"
Circular::Circular(float r)
{
this->r = r;
}
float Circular::GetLength()
{
//2πr
return 2 * 3.14f * r;
}
float Circular::GetArea()
{
//πr²
return 3.14f * r * r;
}
Lesson25_练习题.cpp
#include <iostream>
#include "Person.h"
#include "Dog.h"
#include "Cat.h"
#include "Rect.h"
#include "Square.h"
#include "Circular.h"
using namespace std;
int main()
{
#pragma region 练习题一
/*写一个动物抽象类,写三个子类
人叫,狗叫,猫叫*/
Animal* p = new Person();
p->Speak();
delete p;
p = nullptr;
Animal* d = new Dog();
d->Speak();
delete d;
d = nullptr;
Animal* c = new Cat();
c->Speak();
delete c;
c = nullptr;
//你好
//汪汪
//喵喵
#pragma endregion
#pragma region 练习题二
/*创建一个图形类,有求面积和周长两个方法
创建矩形类,正方形类,圆形类继承图形类
实例化矩形、正方形、圆形对象求面积和周长*/
Graph* g = new Rect(5, 6);
cout << g->GetLength() << endl;
cout << g->GetArea() << endl;
delete g;
g = nullptr;
g = new Square(5);
cout << g->GetLength() << endl;
cout << g->GetArea() << endl;
delete g;
g = nullptr;
g = new Circular(3);
cout << g->GetLength() << endl;
cout << g->GetArea() << endl;
delete g;
g = nullptr;
//22
//30
//20
//25
//18.84
//28.26
#pragma endregion
}
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com