2011-03-11 63 views
9

Tôi có các lớp:C++ đa hình và mặc định luận

class Base 
{ 
    public: 
     virtual void foo(int x = 0) 
     { 
      printf("X = %d", x); 
     } 
}; 

class Derived : public Base 
{ 
    public: 
     virtual void foo(int x = 1) 
     { 
      printf("X = %d", x); 
     } 
};

Khi tôi có:

Base* bar = new Derived(); 
bar->foo();

đầu ra của tôi là "X = 0", ngay cả khi foo được gọi là từ nguồn gốc, nhưng khi Tôi có:

Derived* bar = new Derived(); 
bar->foo();

Kết quả của tôi là "X = 1". Hành vi này có đúng không? (Để chọn giá trị tham số mặc định từ kiểu khai báo, thay vì chọn nó từ kiểu đối tượng thực tế). Điều này có phá vỡ sự đa hình C++ không?

Có thể gây ra nhiều sự cố nếu ai đó sử dụng các chức năng ảo mà không chỉ định tham số chức năng thực tế và sử dụng thông số mặc định của hàm.

+1

đặt nội dung nào đó trong printf() thực sự cho bạn biết chức năng nào đang được gọi là – Ferruccio

+0

Rõ ràng là hàm được gọi là Derived :: foo – Felics

+0

Làm cách nào? cả hai đều in một cái gì đó như "X = giá trị". Bạn không thể sử dụng giá trị để xác định giá trị nào đang được gọi. Hãy thử in "Base: X =% d" trong cơ sở và bạn sẽ có thể biết cái nào được gọi. – Ferruccio

Trả lời

5

Đối số mặc định được giữ lại ngay cả khi bạn ghi đè hàm! Và hành vi này là chính xác. Hãy để tôi tìm kiếm tham chiếu từ tiêu chuẩn C++.

§8.3.6/10 [Mặc định lập luận] từ ++ Chuẩn C nói,

Một cuộc gọi chức năng ảo (10,3) sử dụng các đối số mặc định trong khai báo của hàm ảo xác định bởi loại tĩnh của con trỏ hoặc tham chiếu biểu thị đối tượng . Chức năng ghi đè trong lớp học bắt buộc không nhận được các đối số mặc định từ hàm này ghi đè.

Ví dụ từ Standard tự

struct A { 
    virtual void f(int a = 7); 
}; 
struct B : public A { 
    void f(int a); 
}; 
void m() 
{ 
    B* pb = new B; 
    A* pa = pb; 
    pa->f(); //OK, calls pa->B::f(7) 
    pb->f(); //error: wrong number of arguments for B::f() 
} 

Ngoài ra, không chỉ nó giữ lại, nó được đánh giá mọi chức năng được gọi là:

§8.3.6/9 cho biết,

Đối số mặc định được đánh giá mỗi khi hàm được gọi là

+0

@Nawaz: Sao chép/dán từ một câu trả lời khác thay vì liên kết với nó không thực sự giúp SO như một toàn thể. Đặc biệt là khi ai đó đã cung cấp liên kết. – Jon

+0

@Jon: Sao chép dán câu trả lời nào khác? Bạn có nghĩa là tôi sao chép dán từ câu trả lời khác? Câu trả lời nào? – Nawaz

+0

@Jon: Được rồi. Tôi nói câu trả lời của bạn NGAY BÂY GIỜ. Nhưng nếu bạn nghĩ rằng nó trả lời câu hỏi, thì bạn nên nói nó là chủ đề trùng lặp và bỏ phiếu để đóng nó! – Nawaz

5

Hành vi là chính xác. Kiểm tra các câu trả lời cho câu hỏi này cho một lời giải thích:

Can virtual functions have default parameters?

đạo đức: điều trị các giá trị tham số mặc định như là một phần của chữ ký chức năng và không thay đổi chúng khi trọng chức năng ảo!

+0

@Jon, cảm ơn vì liên kết, câu trả lời ban đầu chắc chắn nhận được sự ủng hộ từ tôi ... – Nim

+0

@Jon: Nếu bạn nghĩ liên kết này trả lời câu hỏi, thì bạn nên bỏ phiếu để đóng chủ đề này, có thể trùng lặp! – Nawaz

+0

@Nawaz: như tôi đã nói: câu trả lời * cho câu hỏi đó cũng trả lời câu hỏi này. Các câu hỏi là * không * giống nhau. – Jon

0

Đây là những gì C++ thiết kế, tôi nghĩ vậy.

Đa hình được hoàn thành bởi bảng ảo, trong đó phát nội bộ bằng con trỏ đến hàm, nhưng giá trị mặc định của thông số không được lưu với con trỏ hàm, nó được liên kết trong giai đoạn biên dịch, vì vậy nó chỉ có thể nhận giá trị mặc định trước tiên nhìn vào kiểu của nó, trong trường hợp đầu tiên của bạn, nó là Base, sau đó nó sử dụng 0 làm giá trị mặc định.

+0

Điều này là chính xác về mặt kỹ thuật, nhưng gây hiểu lầm như một câu trả lời vì tiêu chuẩn C++ không ủy quyền rằng đa hình được thực hiện bởi vtables. Nó nêu rõ điều gì sẽ xảy ra trong các tình huống như vậy; nếu nó để lại rằng không xác định như là một chi tiết thực hiện, sau đó bất cứ ai có thể viết một trình biên dịch phù hợp sử dụng một cơ chế như vtable để ràng buộc các giá trị mặc định. – Jon

+0

Có. Nhưng đối với những người làm việc theo tiêu chuẩn, họ cũng nghĩ liệu tính năng này có thực tế hay không. Tôi chỉ nghĩ rằng nó được thiết kế theo cách này bởi vì cách khác là không thực tế. Bất kỳ chức năng nào cũng có thể thực hiện rất nhiều paremters tất cả chúng đều có giá trị mặc định. Điều đó làm cho thời gian chạy liên kết một nhiệm vụ không thể. – Shuo