Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> C++

Virtual Functions สามารถมี Default Parameters ได้ไหมใน C++?

ได้** Virtual functions ใน C++ สามารถมี default parameters ได้ แต่มีพฤติกรรมพิเศษที่ต้องระวัง

กฎสำคัญ: Default Parameters ผูกที่ Compile-time (Static Binding)

  • Default arguments **ไม่ได้เป็นส่วนหนึ่งของ function signature**
  • Default value ถูก.resolve() ที่ **compile-time** ตาม **static type** ของ pointer/reference
  • Function ที่ถูกเรียก (dynamic dispatch) ถูกตัดสินใจที่ **runtime** ตาม **dynamic type**

ตัวอย่างแสดงพฤติกรรม

#include <iostream>

using namespace std;

class Base {
public:
    virtual void func(int x = 10) {  // Default = 10
        cout << "Base::func(" << x << ")\n";
    }
};

class Derived : public Base {
public:
    void func(int x = 20) override {  // Default = 20 (ต่างจาก Base!)
        cout << "Derived::func(" << x << ")\n";
    }
};

int main() {
    Derived d;
    Base* bp = &d;
    Base& br = d;
    
    cout << "--- Direct call (static type Derived) ---\n";
    d.func();      // Derived::func(20) - ใช้ default ของ Derived
    
    cout << "\n--- Via Base pointer (static type Base) ---\n";
    bp->func();    // Derived::func(10) - เรียก Derived แต่ใช้ default ของ Base!
    
    cout << "\n--- Via Base reference (static type Base) ---\n";
    br.func();     // Derived::func(10) - เรียก Derived แต่ใช้ default ของ Base!
    
    cout << "\n--- Explicit arguments ---\n";
    bp->func(99);  // Derived::func(99) - explicit argument
    d.func(99);    // Derived::func(99)
    
    return 0;
}

ผลลัพธ์

--- Direct call (static type Derived) ---
Derived::func(20)

--- Via Base pointer (static type Base) ---
Derived::func(10)

--- Via Base reference (static type Base) ---
Derived::func(10)

--- Explicit arguments ---
Derived::func(99)
Derived::func(99)

การวิเคราะห์

CallStatic TypeDynamic TypeFunction CalledDefault Used
d.func()DerivedDerivedDerived::func20 (Derived)
bp->func()BaseDerivedDerived::func10 (Base)
br.func()BaseDerivedDerived::func10 (Base)
bp->func(99)BaseDerivedDerived::func99 (explicit)

Best Practice: หลีกเลี่ยง Default Parameters ใน Virtual Functions

// ❌ Bad: Default parameters in virtual functions
class Base {
    virtual void foo(int x = 10);
};
class Derived : public Base {
    void foo(int x = 20) override;  // Confusing!
};

// ✅ Good: ใช้ overload แทน
class Base {
public:
    virtual void foo(int x) { /* implementation */ }
    void foo() { foo(10); }  // Non-virtual wrapper with default
};

class Derived : public Base {
public:
    void foo(int x) override { /* implementation */ }
    void foo() { foo(20); }  // Own default
};

อีกแนวทาง: Non-Virtual Interface (NVI) Pattern

class Base {
public:
    // Public non-virtual interface
    void doOperation(int x = 10) {
        // Pre-processing...
        doOperationImpl(x);  // Call private virtual
        // Post-processing...
    }
    
private:
    virtual void doOperationImpl(int x) = 0;  // Pure virtual implementation
};

class Derived : public Base {
private:
    void doOperationImpl(int x) override {
        // Derived-specific implementation
    }
};

สรุป

  • Virtual functions **สามารถ** มี default parameters ได้
  • แต่ **default value ถูกผูกที่ static type** (compile-time)
  • Function body ที่รันคือของ dynamic type (runtime)
  • แนะนำ: หลีกเลี่ยง default parameters ใน virtual functions ใช้ NVI pattern หรือ overload แทน