C++中是否需用final修饰set_height防止重写?附编译影响疑问
问题:是否需要将set_height标记为virtual...final?
假设我有一个类,其封装变量需要进行条件保护,示例代码如下:
class person { private: int height_; public: explicit person(int height) { this->height_ = height; } int get_height() const noexcept { return height_; } void set_height(int height) { if (height < 0) throw std::invalid_argument("Height cannot be negative"); this->height_ = height; } };
我知道可以将height设为unsigned int,但这只是众多可能问题场景的示例。请问是否需要将set_height标记为virtual...final以防止派生类重写?还是默认假设正常情况下不会出现此类重写?另外,这么做会增加编译时间或存在其他负面影响吗?
回答
核心判断:看你的类设计意图
如果你的person类不打算作为基类被继承,那完全没必要加virtual...final——直接把整个类标记为final更干脆,从根源上禁止继承,也就不存在重写的问题了。
如果你的类允许被继承,但必须保证set_height的校验逻辑不被破坏,那一定要给set_height加上final(不需要额外加virtual,除非你原本就打算让它成为虚函数)。因为一旦派生类重写了set_height,很可能会绕过你写的合法性校验,导致height_被设置为非法值,直接破坏类的封装不变式(invariants)。
别依赖“默认假设”
别寄希望于“正常情况下不会重写”——代码维护过程中,后续接手的开发者可能会出于各种原因去重写这个方法。如果校验逻辑是类的核心约束,就必须用代码强制执行,而不是靠口头约定。
负面影响几乎可以忽略
- 编译时间:加
final对编译速度的影响微乎其微,甚至可能因为编译器能做更多优化(比如非虚函数的静态绑定),反而让编译或运行效率更高。 - 运行时开销:
final只是一个编译期标记,不会带来任何运行时性能损耗。唯一的小局限是如果后续真的需要修改设计允许重写,得去掉final,但这种情况在设计明确的前提下很少发生。
额外优化建议
如果你的类允许继承,但希望派生类能扩展校验逻辑而不是完全替换,可以把校验逻辑抽成私有辅助函数,同时补上构造函数的校验漏洞:
class person { private: int height_; void validate_height(int height) { if (height < 0) throw std::invalid_argument("Height cannot be negative"); } public: explicit person(int height) : height_(height) { validate_height(height); // 构造时也要校验,避免对象初始状态非法 } int get_height() const noexcept { return height_; } virtual void set_height(int height) { validate_height(height); height_ = height; } };
这样派生类重写时,只要调用validate_height就能保证基础校验不被跳过,同时可以添加自己的逻辑:
class adult : public person { public: void set_height(int height) override { validate_height(height); // 保留基础校验 if (height > 250) throw std::invalid_argument("Adult height cannot exceed 250cm"); person::set_height(height); } };
内容的提问来源于stack exchange,提问作者Bard
相关产品推荐
相关产品推荐

