Hành vi mặc định của method về tính virtual (có thể override) khác biệt căn bản giữa C++ và Java.
C++: Non-virtual by default
- Method mặc định không phải virtual → static binding (compile-time).
- Muốn dynamic dispatch → phải khai báo explicit
virtual. - Destructor nên
virtualnếu class dùng làm base class.
// C++
class Base {
public:
void display() { cout << "Base::display\n"; } // NON-VIRTUAL
virtual void show() { cout << "Base::show\n"; } // VIRTUAL
};
class Derived : public Base {
public:
void display() { cout << "Derived::display\n"; } // HIDES Base::display
void show() override { cout << "Derived::show\n"; } // OVERRIDES Base::show
};
int main() {
Base* ptr = new Derived();
ptr->display(); // Base::display (static binding - NON-VIRTUAL)
ptr->show(); // Derived::show (dynamic binding - VIRTUAL)
delete ptr;
}
Java: Virtual by default
- Tất cả instance methods mặc định là virtual (dynamic binding).
- Không có từ khóa
virtual. - Để làm non-virtual: dùng
final,private,static, hoặcconstructor.
// Java
class BaseClass {
public void displayMsg() { // VIRTUAL by default
System.out.println("BaseClass displayMsg");
}
final void cannotOverride() { } // NON-VIRTUAL (final)
private void internal() { } // NON-VIRTUAL (private)
static void classMethod() { } // NON-VIRTUAL (static)
}
class DerivedClass extends BaseClass {
@Override
public void displayMsg() { // OVERRIDE
System.out.println("DerivedClass displayMsg");
}
// void cannotOverride() { } // COMPILE ERROR: cannot override final
// void internal() { } // OK: private method không visible, không override
// static void classMethod() { } // HIDING, không override
}
public class Main {
public static void main(String[] args) {
BaseClass obj = new DerivedClass();
obj.displayMsg(); // DerivedClass displayMsg (DYNAMIC BINDING)
}
}
Bảng so sánh
| Đặc điểm | C++ | Java |
|---|---|---|
| Instance method mặc định | Non-virtual (static binding) | Virtual (dynamic binding) |
| Từ khóa bật virtual | virtual | Mặc định (không cần keyword) |
| Từ khóa tắt virtual | Không có (chỉ bỏ virtual) | final, private, static |
| Destructor | Cần virtual cho base class | Không có destructor (finalize() deprecated, dùng try-with-resources/Cleaner) |
| Static method | Non-virtual (class-level) | Non-virtual (class-level, hiding) |
| Multiple inheritance | Có (virtual inheritance cho diamond) | Không (interface default method giải quyết một phần) |
Tại sao Java chọn Virtual by default?
- Thiết kế OOP thuần túy: polymorphism là mặc định, encapsulation hành vi.
- Tránh lỗi quên
virtualdẫn đến sai hành vi (common C++ bug). - Interface-based design: tất cả method interface là virtual.
- JVM tối ưu dynamic dispatch tốt (inline caching, CHA – Class Hierarchy Analysis).
Performance Note
- C++: Non-virtual = direct call (fastest). Virtual = v-table lookup (1 indirection).
- Java: Mọi instance call = virtual call. Nhưng JIT compiler thực hiện devirtualization (inline) khi phát hiện chỉ có 1 implementation tại runtime (monomorphic call site).
- Kết quả: Java virtual call performance ~ C++ non-virtual sau JIT warmup.