📅  最后修改于: 2023-12-03 15:13:59.768000             🧑  作者: Mango
C++ 和 Java 都支持虚拟函数,但是它们的默认虚拟行为有一些不同。本文将从以下几个方面进行介绍:
在 C++ 中,如果一个类的方法被声明为 virtual
,那么它就是一个虚函数。而在 Java 中,如果一个类的方法被声明为 abstract
,那么它就是一个虚函数。
C++ 示例代码:
class Animal {
public:
virtual void speak();
};
class Cat : public Animal {
public:
void speak() override;
};
Java 示例代码:
abstract class Animal {
public abstract void speak();
}
class Cat extends Animal {
public void speak() {
// ...
}
}
在 C++ 中,每个对象都包含一个指向虚函数表(VTable)的指针,因此一个对象的大小比其成员变量的大小大一个指针的大小。而在 Java 中,虚函数表是由虚拟机来维护的,不会影响对象的大小。
C++ 示例代码:
class Animal {
public:
virtual void speak();
private:
int age;
char *name;
};
class Cat : public Animal {
public:
void speak() override;
private:
char *color;
};
int main() {
cout << sizeof(Animal) << endl; // 8 or 16 (depending on machine)
cout << sizeof(Cat) << endl; // 16 or 32 (depending on machine)
return 0;
}
Java 示例代码:
abstract class Animal {
public abstract void speak();
}
class Cat extends Animal {
private int age;
private String name;
private String color;
public void speak() {
// ...
}
}
public class Main {
public static void main(String[] args) {
System.out.println(ObjectSizeCalculator.getObjectSize(new Cat()));
}
}
// Output: 40 or 48 (depending on JVM and platform)
在 C++ 中,每个有虚函数的类都有一个虚函数表。虚函数表是一个包含指向虚函数的指针的数组,每个对象都有一个指向其所属类的虚函数表的指针。当调用一个虚函数时,实际上是通过对象指针中的虚函数表指针找到虚函数表,并在其中找到指向实际函数的指针,然后进行调用。
C++ 示例代码:
class Animal {
public:
virtual void speak();
};
class Cat : public Animal {
public:
void speak() override;
};
int main() {
Animal *a = new Cat();
a->speak(); // Calls Cat's speak() method
return 0;
}
在上面的示例代码中,a
实际上是一个 Cat
对象的指针,但是它的静态类型为 Animal
。当执行 a->speak()
时,调用的实际上是 Cat
类中的 speak()
方法,但是这是通过虚函数表来实现的。
而在 Java 中,继承树的静态结构已经在编译时确定了,虚表也在编译时被创建。当调用一个虚函数时,虚拟机直接找到虚函数表中指向实际函数的指针,然后进行调用。
Java 示例代码:
abstract class Animal {
public abstract void speak();
}
class Cat extends Animal {
public void speak() {
// ...
}
}
public class Main {
public static void main(String[] args) {
Animal a = new Cat();
a.speak(); // Calls Cat's speak() method
}
}
在 C++ 中,如果一个类继承自多个类,那么它就需要解决菱形继承的问题。C++ 使用虚拟继承(Virtual Inheritance)的方式来解决这个问题。在虚拟继承的情况下,虚函数表指针不是在对象中存储的,而是通过一个指向共享虚函数表的指针来共享。
C++ 示例代码:
class Animal {
public:
virtual void speak();
};
class Mammal : virtual public Animal {
public:
void lactate();
};
class Bird : virtual public Animal {
public:
void fly();
};
class Platypus : public Mammal, public Bird {
public:
void layEggs();
};
int main() {
Platypus p;
p.speak(); // Calls Animal's speak() method
return 0;
}
而在 Java 中,由于不允许多重继承,因此不存在菱形继承的问题,也就不需要虚拟继承的方式来解决。
Java 示例代码:
abstract class Animal {
public abstract void speak();
}
class Bird extends Animal {
public void fly() {
// ...
}
}
class Mammal extends Animal {
public void lactate() {
// ...
}
}
class Platypus extends Mammal {
public void layEggs() {
// ...
}
}
public class Main {
public static void main(String[] args) {
Platypus p = new Platypus();
p.speak(); // Calls Mammal's speak() method
}
}
C++ 和 Java 都支持虚函数,但是它们的默认虚拟行为有一些不同。C++ 中每个对象都包含一个指向虚函数表的指针,而 Java 中虚函数表是由虚拟机来维护的。另外,在多重继承的情况下,C++ 使用虚拟继承来解决菱形继承的问题,而 Java 不允许多重继承,因此不存在菱形继承的问题。