什么是对象的动态类型?

15
我认为动态类型指的是使用new动态分配的对象。在下面的情况中,你认为p指向的是动态类型还是静态类型?在标准中,并没有说明动态类型是动态对象。

1.3.3 - lvalue表达式所表示的lvalue引用的最派生对象(1.8)的类型。[例如:如果指针(8.3.1)p的静态类型为“指向类B的指针”,指向从B(条款10)派生出来的D类的对象,则表达式*p的动态类型为“D”。参考文献(8.3.2)也类似处理。]

此外,以下引用的含义是什么?

rvalue表达式的动态类型是它的静态类型

class Base {
    virtual void foo(){}
};

class Derived : public Base {
    void foo(){}
};

int main()
{
    Derived d;
    Base *p = &d;
}
4个回答

27

我认为动态类型意味着使用new动态分配的对象。

不是这样的。

动态类型是一个真实的类型,可以通过指向其基本类型的引用(包括指针)访问该类型的对象。

也就是说,如果我们有:

class A {

};

class B : public A { };


B l;
A& k = l;

这里的k是类型A的一个对象的引用,但被引用的对象的实际类型,也就是它的动态类型,是B。

这里的“动态”是指“仅在运行时才知道”。


3
+1,但我认为您可以通过添加一个完全不使用“new”的示例来使示例更加清晰。 - San Jacinto
A &k = B(); 不就可以了吗? - arne
在我的例子中,我有虚函数,这意味着调用将在运行时解析。当没有动态绑定时,动态如何应用于此处? - user103214
@user974191,您的意思是实现继承的方式吗?或许可以搜索一下“虚拟表”。在您的例子中,“动态类型”也就是“运行时真正已知的类型”显然是Derived。然而,在某些代码中,您可以使用一个基类类型,而不必知道它实际上是别的什么东西。 - Klaim
@arne,你正在使用一个非const引用与临时变量。这甚至无法编译。如果我没记错的话,使用const引用就可以了。 - Klaim

6

静态类型是变量的类型,在编译时已知(因此被认为是静态的 - 不能更改)。动态类型是在运行时实际被指向的对象的类型。这里的动态意味着它只在运行时已知,这意味着它可能会发生变化(即一个变量可以指向各种类型的不同对象)。

在这段内容中,使用new与你的示例无关。在您的主函数中,d的静态和动态类型均为Derived,因为它不是指针或引用。但是,p的静态类型为Base,但在您的代码中,动态类型将是Derived


*p 不是一个变量,它是一个表达式。 - curiousguy

5
在静态类型语言(如C++或Java)中,“static”可能指的是编译时已知的信息,而“dynamic”则指运行时已知的信息。
例如:
struct Base { virtual std::string name() const { return "Base"; } };

struct Derived: Base { std::string name() const { return "Derived"; } };

void print(Base const& b) { std::cout << b.name() << "\n"; }

print方法中,bstatic类型为Base const&, 因此编译器将检查在Base对象上下文中调用的所有方法是否存在。
然而,当执行时,由于该方法是虚拟的,因此调用name方法会根据对象的dynamic类型进行操作:
  • 这可能是Base
  • 这可能是Derived
  • 这可能是我们尚未知道的另一个派生自Base的类
因此,在以下示例中:
int main(int argc, char* argv[]) {
  if (argc == 1) {
    Base base;
    print();
  } else {
    Derived derived;
    print(derived);
  }
};
  • base 的静态类型和动态类型都是 Base,而 derived 的静态类型和动态类型都是 Derived
  • print 方法中,b 的静态类型始终为 Base
  • 根据参数数量的不同,b 的动态类型可能是 Base 或者 Derived

假设多态性必须基于动态内存分配是一种错误的想法,虽然这两个概念并不是正交的,但在某些情况下可以在没有彼此的情况下使用。


-2

动态内存分配总是在运行时完成,可以使用“new”关键字实现。 但是,在您的问题中还有另一种情况,如*p=&d,因为您已将基类函数“Virtual”设置为告诉编译器按其内容而不是指针类型来处理“p”。所以这是动态内存分配之一,因为编译器永远不知道您要在运行时存储哪个类对象的地址,它只知道它是哪种类型的指针(即基类指针或派生类指针)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接