c++的静态类型和动态类型(二)

本文有两处小细节可以更严谨:

  1. "静态类型语言"之外的补充 :下文里说"在使用基类指针/引用时才会涉及动态类型",这是常见的实用说法。严格按标准,glvalue 的动态类型指它所引用的最派生对象的类型,只是对非多态类来说你无法通过 typeid/dynamic_cast 观察到它。
  2. Derived::bar() 的写法 :它隐藏(hide)了 Base::bar,而不是重写。这个例子本来就是想演示"非虚函数按静态类型选择",所以没问题,只是如果想学习,值得明确说一句"这是隐藏,不是覆盖"。

C++ 的静态类型和动态类型

C++ 是静态类型语言 :变量、表达式、函数参数等的类型在编译期就确定了,这叫静态类型。

同时,C++ 通过继承 + 虚函数支持运行期多态,所以在使用基类指针/引用 操作对象时,才会涉及动态类型:对象在运行时实际是什么类型。

看例子:

cpp 复制代码
#include <iostream>
#include <typeinfo>

class Base {
public:
    virtual ~Base() = default;  // 有虚函数,Base 是多态类型
    virtual void foo() const { std::cout << "Base::foo\n"; }
    void bar() const { std::cout << "Base::bar\n"; }
};

class Derived : public Base {
public:
    void foo() const override { std::cout << "Derived::foo\n"; }
    void bar() const { std::cout << "Derived::bar\n"; }
    void extra() const { std::cout << "Derived::extra\n"; }
};

int main() {
    Derived d;

    Base* p = &d;   // p 的静态类型是 Base*
                    // *p 的静态类型是 Base
                    // *p 的动态类型是 Derived

    Base& r = d;    // r 的静态类型是 Base&
                    // r 的动态类型是 Derived

    p->foo();       // 输出 Derived::foo,虚函数按动态类型调用
    p->bar();       // 输出 Base::bar,非虚函数按静态类型调用
    r.foo();        // 输出 Derived::foo

    // p->extra();  // 编译错误!编译器只看静态类型 Base*,看不到 extra

    if (typeid(*p) == typeid(Derived)) {
        std::cout << "p 指向的对象动态类型是 Derived\n";
    }

    if (Derived* q = dynamic_cast<Derived*>(p)) {
        q->extra(); // 输出 Derived::extra
    }

    Base b = d;     // 对象切片:b 的静态类型和动态类型都是 Base
    b.foo();        // 输出 Base::foo
}

核心区别

概念 静态类型 动态类型
确定时机 编译期 运行期
依据 变量/表达式声明类型 指针/引用实际指向的对象类型
用途 类型检查、重载解析、模板、非虚函数调用 虚函数分派、typeid、dynamic_cast
例子 Base* p 的静态类型是 Base* p 指向 Derived 时,*p 的动态类型是 Derived

一句话总结:

静态类型是编译器看到的类型;动态类型是运行时对象真正的类型。

在 C++ 中,动态类型主要通过虚函数 和 RTTI 起作用。



小写字母 a 的 ASCII 编码值是:

  • 十进制:97
  • 十六进制:0x61
  • 八进制:141
  • 二进制:01100001

补充:大写字母 A 的 ASCII 值是 65。在常见 C++ 实现中,int('a') == 97;不过 C++ 标准本身不强制一定使用 ASCII,但主流平台基本都是 ASCII/UTF-8 兼容。

相关推荐
吠品1 小时前
箭头函数为什么不能 new
开发语言·javascript·原型模式
stolentime1 小时前
AT_arc182_a [ARC182A] Chmax Rush!题解
数据结构·c++·算法·动态规划
longlongzihan1 小时前
LeetCode 189. 轮转数组:从直观模拟到最优原地算法
c++·算法·leetcode
谢亮_vipxieliang2 小时前
PHP 8 新特性:构造器属性提升与实战
开发语言·后端·php
鬼手点金2 小时前
opencode-crawl4ai使用建议
java·开发语言·人工智能·python·机器学习
谢亮_vipxieliang2 小时前
Go select 多路复用:从语法到实战的完整指南
开发语言·后端·golang
2601_9628857212 小时前
如何用 Python 自动识别股票的支撑位与压力位?
开发语言·python
爱吃奥利奥_wen12 小时前
面向对象三板斧:封装、继承、多态,到底在“装“什么、“承“什么、“变“什么?
开发语言·经验分享·c#
All for pursuit.12 小时前
【位运算-1】338.比特位计数
数据结构·c++·算法·leetcode