为什么 C++ 编译器不能知道指针指向派生类?

Ver*_*sed 1 c++ compiler-construction oop pointers

我刚刚开始学习 C++ 中的 OOP。我想知道为什么需要使用 virtual 关键字来指示编译器进行后期绑定?为什么编译器在编译时不能知道指针指向派生类?

class A { 
    public: int f() { return 'A';}
};

class B : public A {
    public: int f() { return 'B';}
};

int main() {

    A* pa;
    B b;
    pa = &b; 
    cout << pa->f() << endl;
}
Run Code Online (Sandbox Code Playgroud)

Cor*_*mer 5

关于在编译时不知道,通常情况下行为仅在运行时才知道。考虑这个例子

#include <iostream>

struct A {};
struct B : A {};
struct C : A {};

int main()
{
    int x;
    std::cin >> x;
    A* a = x == 1 ? new B : new C;
}
Run Code Online (Sandbox Code Playgroud)

在这个例子中,编译器如何知道是否a会指向 aB*C*?它不能,因为行为取决于运行时值。


Bat*_*eba 5

它怎么会(完全一般)?例如

#include <cstdlib>
struct Parent {};
struct Child : Parent {};

int main()
{
    Parent* p = std::rand() % 2 ? new Parent() : new Child();
}
Run Code Online (Sandbox Code Playgroud)


Som*_*ude 5

假设您有一个简单的类层次结构,例如

class Animal
{
    // Generic animal attributes and properties
};

class Mammal : public Animal
{
    // Attributes and properties specific to mammals
};

class Fish : public Animal
{
    // Attributes and properties specific to fishes
};

class Cat : public Mammal
{
    // Attributes and properties specific to cats
};

class Shark : public Fish
{
    // Attributes and properties specific to sharks
};

class Hammerhead : public Shark
{
    // Attributes and properties specific to hammerhead sharks
};
Run Code Online (Sandbox Code Playgroud)

[有点啰嗦,但我想让“具体”类彼此远离]

现在让我们说我们有一个像

void do_something_with_animals(Animal* animal);
Run Code Online (Sandbox Code Playgroud)

最后让我们调用这个函数:

Fish *my_fish = new Hammerhead;
Mammal* my_cat = new Cat;

do_something_with_animals(my_fish);
do_something_with_animals(my_cat);
Run Code Online (Sandbox Code Playgroud)

现在,如果我们稍微思考一下,在do_something_with_animals函数中确实无法确切知道参数animal可能指向什么。是Mammal吗?一个Fish?特定的Fish子类型?

如果do_something_with_animals函数是在不同的翻译单元中定义的,这对编译器来说就更难了,而MammalFish类(或其任何子类)的定义甚至可能不可用。