推荐B站视频:C++现代实用教程(四):面向对象核心多态_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV15v4y1M7fF/?spm_id_from=333.999.0.0&vd_source=a934d7fc6f47698a29dac90a922ba5a3
本项目通用的tasks.json文件和launch.json
- tasks.json
{"version": "2.0.0","options": {"cwd": "${workspaceFolder}/build"},"tasks": [{"type": "shell","label": "cmake","command": "cmake","args": [".."]},{"label": "make","group": "build","command": "make","args": [],"problemMatcher": []},{"label": "Build","dependsOrder": "sequence","dependsOn": ["cmake","make"]},{"type": "cppbuild","label": "C/C++: g++ 生成活动文件",// "command": "/usr/bin/g++","command": "D://mingw64//bin//g++.exe","args": ["-fdiagnostics-color=always","-g","-o","${workspaceFolder}/bin/app.exe",// "-finput-charset=UTF-8",/*-fexec-charset指定输入文件的编码格式-finput-charset指定生成可执行的编码格式,*/"-finput-charset=GBK", // 处理mingw中文编码问题"-fexec-charset=GBK"],"options": {"cwd": "${workspaceFolder}"},"problemMatcher": ["$gcc"],"group": {"kind": "build","isDefault": true},"detail": "D://mingw64//bin//g++.exe"}]
}
- launch.json
{// 使用 IntelliSense 了解相关属性。 // 悬停以查看现有属性的描述。// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387"version": "0.2.0","configurations": [{"name": "(gdb) 启动","type": "cppdbg","request": "launch","program": "${workspaceFolder}/bin/app.exe","args": [],"stopAtEntry": false,"cwd": "${workspaceFolder}","environment": [],"externalConsole": false,"MIMode": "gdb","setupCommands": [{"description": "为 gdb 启用整齐打印","text": "-enable-pretty-printing","ignoreFailures": true,},],"preLaunchTask": "Build","miDebuggerPath": "D://mingw64//bin//gdb.exe", // 修改为你的 gdb 路径},]
}
- CMakeLists.txt
cmake_minimum_required(VERSION 3.28.0)
project(project)
include_directories(${PROJECT_SOURCE_DIR}/include)
aux_source_directory(${PROJECT_SOURCE_DIR}/src SRC_LIST)add_executable(app main.cpp ${SRC_LIST})
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
C++的面向对象与很多其他的面向对象语言有很多不同,本质的原因是在于C++是一门极其重视性能的编程语言
>>多态是面向对象的核心
- 这一点对于C++来说也不例外
- 面向对象的三大特性为:封装、继承、多态
- 本人不是很喜欢C++的继承,其实是不喜欢继承
- 封装和继承基本上是为多态而准备的
- 面向对象是使用多态性获得对系统中每个源代码依赖项的绝对控制的能力的(大牛说的)
- 高内聚、低耦合是程序设计的目标(无论是否面向对象,),而多态是实现高内聚,低耦合的基础
>>目录
1.多态与静态绑定2.虚函数与动态绑定3.多态对象的应用场景与大小4.Override与Final5.Overloading与多态6.析构函数与多态7.Dynamic_cast类型转换8.typeid操作符9.纯虚函数与抽象类10.接口式抽象类
第一节:多态与静态绑定
>>多态:
- 在编程语言和类型论中,多态(英语:polymorphism)指为不同数据类型的实体提供统一的接口
- 多态意味着调用成员函数时,会根据调用函数的对象的类型来执行不同的函数
>>静态绑定:将名称绑定到一个固定的函数定义,然后在每次调用该名称时执行该定义,这个也是常态执行的方式
- shape.h
#ifndef SHAPE_H
#define SHAPE_H
#include <string>
#include <string_view>
#include <iostream>
class Shape{
public:Shape() = default;~Shape() = default;Shape(std::string_view name);void draw() const {std::cout<<"Shape Drawing "<<m_name<<std::endl;}
protected:std::string m_name;
};
#endif
- shape.cpp
#include "shape.h"Shape::Shape(std::string_view name) : m_name(name){}
- rectangle.h
#ifndef RECTANGLE_H
#define RECTANGLE_H
#include <string>
#include <string_view>
#include <iostream>
#include "shape.h"
class Rectangle:public Shape{
public:Rectangle() = default;~Rectangle() = default;Rectangle(double x,double y,std::string_view name);void draw() const {std::cout<<"Rectangle Drawing "<<m_name<<" with x: "<<get_x()<<",y: "<<get_y()<<std::endl;}
protected:double get_x() const{return m_x;}double get_y() const{return m_y;}
private:double m_x{0.0};double m_y{0.0};
};
#endif
- rectangle.cpp
#include "rectangle.h"Rectangle::Rectangle(double x, double y,std::string_view name): Shape(name),m_x(x),m_y(y)
{}
- square.h
#ifndef SQUARE_H
#define SQUARE_H
#include "rectangle.h"
class Square:public Rectangle{
public:Square() = default;~Square() = default;Square(double x,std::string_view name);void draw() const {std::cout<<"Square Drawing "<<m_name<<" with x: "<<get_x()<<std::endl;}
};
#endif
- square.cpp
#include "square.h"Square::Square(double x, std::string_view name): Rectangle(x,x,name)
{
}
- main.cpp
#include <iostream>
#include "square.h"
#include "rectangle.h"
#include "shape.h"
using namespace std;// Shape -> Rectangle -> Square
// draw()
void test1() {// 静态绑定的不足Shape s1("Shape1");s1.draw();// Shape Drawing Shape1Rectangle r1(1.0,2.0,"Rectangle1");r1.draw();// Rectangle Drawing Rectangle1 with x: 1,y: 2Square sq1(3.0,"Square1");sq1.draw();// Square Drawing Square1 with x: 3// Base PointerShape* shape_ptr = &s1;shape_ptr->draw();// Shape Drawing Shape1shape_ptr = &r1;shape_ptr->draw();// Shape Drawing Rectangle1shape_ptr = &sq1;shape_ptr->draw();// Shape Drawing Square1
}int main(int argc,char* argv[]) {test1();cout<<"over~"<<endl;return 0;
}
- 执行结果:
PS D:\Work\C++UserLesson\cppenv\static_bind\build> ."D:/Work/C++UserLesson/cppenv/static_bind/bin/app.exe"
Shape Drawing Shape1
Rectangle Drawing Rectangle1 with x: 1,y: 2
Square Drawing Square1 with x: 3
Shape Drawing Shape1
Shape Drawing Rectangle1
Shape Drawing Square1
over~
PS D:\Work\C++UserLesson\cppenv\static_bind\build>
第二节:虚函数与动态绑定
>>动态绑定
- 实现继承
- 父类、子类需要动态绑定的函数设置为虚函数
- 创建父类指针/引用(推荐指针)指向子类对象,然后调用
>>虚函数
- 虚函数是应在派生类中重新定义的成员函数
- 关键字为virtual
通过例子来实现多态
- shape.h
#ifndef SHAPE_H
#define SHAPE_H
#include <string>
#include <string_view>
#include <iostream>
class Shape{
public:Shape() = default;~Shape() = default;Shape(std::string_view name);virtual void draw() const {std::cout<<"Shape Drawing "<<m_name<<std::endl;}
protected:std::string m_name;
};
#endif
- shape.cpp
#include "shape.h"Shape::Shape(std::string_view name) : m_name(name){}
- rectangle.h
#ifndef RECTANGLE_H
#define RECTANGLE_H
#include <string>
#include <string_view>
#include <iostream>
#include "shape.h"
class Rectangle:public Shape{
public:Rectangle() = default;~Rectangle() = default;Rectangle(double x,double y,std::string_view name);virtual void draw() const {std::cout<<"Rectangle Drawing "<<m_name<<","<<"x: "<<get_x()<<",y: "<<get_y()<<std::endl;}
protected:double get_x() const{return m_x;}double get_y() const{return m_y;}
private:double m_x{0.0};double m_y{0.0};
};
#endif
- rectangle.cpp
#include "rectangle.h"Rectangle::Rectangle(double x, double y,std::string_view name): Shape(name),m_x(x),m_y(y)
{}
- square.h
#ifndef SQUARE_H
#define SQUARE_H
#include "rectangle.h"
class Square:public Rectangle{
public:Square() = default;~Square() = default;Square(double x,std::string_view name);void draw() const {std::cout<<"Square Drawing "<<m_name<<" with x: "<<get_x()<<std::endl;}
};
#endif
- square.cpp
#include "square.h"Square::Square(double x, std::string_view name): Rectangle(x,x,name)
{
}
- 执行结果:
PS D:\Work\C++UserLesson\cppenv\dynamic_bind\bin> ."D:/Work/C++UserLesson/cppenv/dynamic_bind/bin/app.exe"
Shape Drawing Shape1
Rectangle Drawing Rectangle1,x: 1,y: 2
Square Drawing Square1 with x: 3
over~
PS D:\Work\C++UserLesson\cppenv\dynamic_bind\bin>
第三节:多态对象的应用场景与大小
(1)多态的两个应用场景
- 函数
- 存储进入Collections
(2)多态与Collection
- 可以存储值类型(并不满足多态)
- 可以存储指针类型
- 不可以存储引用
(3)通过例子来
- 多态的两大应用场景
注意:这里的源文件和头文件和第二节的一样!
(1)Base Pointers
#include <iostream>
#include "square.h"
#include "rectangle.h"
#include "shape.h"
using namespace std;void draw_shape(Shape* s) {s->draw();
}// Shape -> Rectangle -> Square
// draw()
void test1() {Shape s1("Shape1");Rectangle r1(1.0,2.0,"Rectangle1");Square sq1(3.0,"Square1");// Base PointersShape* shape_ptr = &s1;draw_shape(shape_ptr);shape_ptr = &r1;draw_shape(shape_ptr);shape_ptr = &sq1;draw_shape(shape_ptr);
}int main(int argc,char* argv[]) {test1();cout<<"over~"<<endl;return 0;
}
执行结果:
PS D:\Work\C++UserLesson\cppenv\dynamic_application\bin> ."D:/Work/C++UserLesson/cppenv/dynamic_application/bin/app.exe"
Shape Drawing Shape1
Rectangle Drawing Rectangle1,x: 1,y: 2
Square Drawing Square1 with x: 3
over~
PS D:\Work\C++UserLesson\cppenv\dynamic_application\bin>
(2)多态与Collection
- 可以存储值类型(并不满足多态)
#include <iostream>
#include "square.h"
#include "rectangle.h"
#include "shape.h"
using namespace std;void draw_shape(Shape* s) {s->draw();
}// Shape -> Rectangle -> Square
// draw()
void test1() {Shape s1("Shape1");Rectangle r1(1.0,2.0,"Rectangle1");Square sq1(3.0,"Square1");// collection cout<<"*********collection*********"<<endl;Shape shapes[]{s1,r1,sq1}; // 不符合多态for(Shape &s:shapes) {s.draw();}
}int main(int argc,char* argv[]) {test1();cout<<"over~"<<endl;return 0;
}
执行结果:
PS D:\Work\C++UserLesson\cppenv\dynamic_application\bin> ."D:/Work/C++UserLesson/cppenv/dynamic_application/bin/app.exe"
*********collection*********
Shape Drawing Shape1
Shape Drawing Rectangle1
Shape Drawing Square1
over~
PS D:\Work\C++UserLesson\cppenv\dynamic_application\bin>
(2)多态与Collection
- 可以存储指针类型
#include <iostream>
#include "square.h"
#include "rectangle.h"
#include "shape.h"
using namespace std;void draw_shape(Shape* s) {s->draw();
}// Shape -> Rectangle -> Square
// draw()
void test1() {Shape s1("Shape1");Rectangle r1(1.0,2.0,"Rectangle1");Square sq1(3.0,"Square1");// Pointercout<<"*********Pointer*********"<<endl;Shape* shapes_ptr[]{&s1,&r1,&sq1};for(Shape* s:shapes_ptr) {s->draw();}
}int main(int argc,char* argv[]) {test1();cout<<"over~"<<endl;return 0;
}
执行结果:
PS D:\Work\C++UserLesson\cppenv\dynamic_application\bin> ."D:/Work/C++UserLesson/cppenv/dynamic_application/bin/app.exe"
*********Pointer*********
Shape Drawing Shape1
Rectangle Drawing Rectangle1,x: 1,y: 2
Square Drawing Square1 with x: 3
over~
PS D:\Work\C++UserLesson\cppenv\dynamic_application\bin>
(2)多态与Collection
- 不可以存储引用
#include <iostream>
#include "square.h"
#include "rectangle.h"
#include "shape.h"
using namespace std;void draw_shape(Shape* s) {s->draw();
}// Shape -> Rectangle -> Square
// draw()
void test1() {Shape s1("Shape1");Rectangle r1(1.0,2.0,"Rectangle1");Square sq1(3.0,"Square1");// Shape ref // cout<<"*********collection*********"<<endl;Shape &shape_ref[]{s1,r1,sq1}; //error 不允许使用引用的数组
}int main(int argc,char* argv[]) {test1();cout<<"over~"<<endl;return 0;
}
未完待续~