C++11 语言特性3: final 关键字 与 模板模式
1.基本用途
- 修饰类: 该类不能被继承, 即不能派生出子类
- 修饰类成员虚函数: 让其不能被子类重写
视频: www.bilibili.com/video/BV1ei…
2.语法
一般放到 类型名后面 和 方法名与函数体中间
修饰类
struct A { };
// 情况1
struct B final { };
// 情况2
struct C final : public A { };
修饰类成员虚函数
struct A {
// 情况1
virtual void func1() final { }
virtual void func2() = 0;
};
struct C final : public A {
// 情况2
void func2() final override { }
//void func2() override final { }
};
3. 使用场景 - 现象 与 模板模式(设计模式)
3.1 基本场景及限制
对类的限制
struct A { };
struct B final { };
struct C final : public A { };
// error
struct D : public B { }
struct E : public C { }
上述中 B 和 C 都被 final 关键字修饰了而A别没有被修饰, 类型C能正常的继承A
但当尝试从类型B和C 进行派生出子类D 和 E 的时候, 编译器就会报错说不能继承final修饰的类(从其派生)
03-final_keyward.cpp:18:8: error: cannot derive from ‘final’ base ‘B’ in derived type ‘D’
18 | struct D : public B { };
| ^
03-final_keyward.cpp:19:8: error: cannot derive from ‘final’ base ‘C’ in derived type ‘E’
19 | struct E : public C { };
|
修饰类成员虚函数
struct A {
virtual void func1() final { }
virtual void func2() = 0;
};
struct C final : public A {
void func1() override { } // error
void func2() final override { }
};
C中可以正常重写(override)基类A中的接口func2 - 虚函数. 而由于func1被 final 关键字修饰后, 在子类C中尝试重写时, 编译器就会报 C::func1 重写 A::func1 的错误
03-final_keyward.cpp:13:10: error: virtual function ‘virtual void C::func1()’ overriding final function
13 | void func1() override { }
| ^~~~~
03-final_keyward.cpp:6:18: note: overridden function is ‘virtual void A::func1()’
6 | virtual void func1() final { }
3.2 多格式音频文件播放 - 接口设计之模板模式
接口设计者 - 至上而下的设计方法
播放流程抽象
播放一个音频文件, 不同的格式有不同的封装格式和编码格式, 大概的一个流程: 读取文件 -> 解决封装 -> 获取音频参数和数据 -> 解码(如果数据有编码的话) -> 配置音频参数 -> 播放 -> 播放结束并释放资源
我们可以简单的把这些流程抽象到 四个过程即:
- 初始化(init)
- 配置(config)
- 播放(play)
- 释放(deinit)
接口设计 - 过程模板
使用 final 关键字 修饰play接口, 使得接口不能被子类重写, 从接口层固定播放的四个过程
每个过程的具体实现交给对应的子类里去实现
class AudioPlayInterface {
// .....
public:
virtual void play() final {
// ... common op
_init();
_config();
_startPlay();
_deinit();
// ... common op
}
protected:
virtual void _init() = 0;
virtual void _config() = 0;
virtual void _startPlay() = 0;
virtual void _deinit() = 0;
// .....
};
接口实现
不同格式的音频文件, 实现AudioPlayInterface里对应的 播放过程的接口
class WAVPlay final : public AudioPlayInterface {
public:
WAVPlay() : AudioPlayInterface("WAV") {
// ...
}
protected:
void _init() override {
std::cout << "WAVPlay: _init" << std::endl;
}
void _config() override {
std::cout << "WAVPlay: _config" << std::endl;
}
void _startPlay() override {
std::cout << "WAVPlay: _startPlay" << std::endl;
}
void _deinit() override {
std::cout << "WAVPlay: _deinit" << std::endl;
}
};
class MP3Play final : public AudioPlayInterface {
public:
MP3Play() : AudioPlayInterface("MP3") {
// ...
}
protected:
void _init() override {
std::cout << "MP3Play: _init" << std::endl;
}
void _config() override {
std::cout << "MP3Play: _config" << std::endl;
}
void _startPlay() override {
std::cout << "MP3Play: _startPlay" << std::endl;
}
void _deinit() override {
std::cout << "MP3Play: _deinit" << std::endl;
}
};
4.测试源码 及 运行结果
测试源码
// g++ -std=c++11 03-final_keyward.cpp
// 基本语法
struct A {
virtual void func1() final { }
virtual void func2() = 0;
};
struct B final { };
struct C final : public A {
// void func1() override { } // error
void func2() final override { }
//void func2() override final { }
};
// error
//struct D : public B { };
//struct E : public C { };
#include <iostream>
#include <string>
class AudioPlayInterface {
protected:
AudioPlayInterface(std::string format) : _mFormat { format } { }
public:
virtual void play() final {
std::cout << "AudioPlayInterface: start -> " << _mFormat << std::endl;
_init();
_config();
_startPlay();
_deinit();
std::cout << "AudioPlayInterface: end..." << std::endl << std::endl;
}
protected:
virtual void _init() = 0;
virtual void _config() = 0;
virtual void _startPlay() = 0;
virtual void _deinit() = 0;
protected:
std::string _mFormat;
// other data
};
class WAVPlay final : public AudioPlayInterface {
public:
WAVPlay() : AudioPlayInterface("WAV") {
// ...
}
protected:
void _init() override {
std::cout << "WAVPlay: _init" << std::endl;
}
void _config() override {
std::cout << "WAVPlay: _config" << std::endl;
}
void _startPlay() override {
std::cout << "WAVPlay: _startPlay" << std::endl;
}
void _deinit() override {
std::cout << "WAVPlay: _deinit" << std::endl;
}
};
class MP3Play final : public AudioPlayInterface {
public:
MP3Play() : AudioPlayInterface("MP3") {
// ...
}
protected:
void _init() override {
std::cout << "MP3Play: _init" << std::endl;
}
void _config() override {
std::cout << "MP3Play: _config" << std::endl;
}
void _startPlay() override {
std::cout << "MP3Play: _startPlay" << std::endl;
}
void _deinit() override {
std::cout << "MP3Play: _deinit" << std::endl;
}
};
int main() {
AudioPlayInterface *wav = new WAVPlay();
AudioPlayInterface *mp3 = new MP3Play();
wav->play();
mp3->play();
delete wav;
delete mp3;
return 0;
}
运行结果