2012-01-26 81 views
10

Tôi có một mẫu lớp trong đó một số phương thức được định nghĩa là ảo để cung cấp khả năng cho người dùng lớp của tôi cung cấp cho chúng trong lớp dẫn xuất của mình. Lưu ý rằng trong lớp mẫu của tôi có một số phương thức không ảo sử dụng ảo (một lớp ảo sẽ trả về một giá trị được gọi trong một lớp không ảo).ghi đè phương pháp ảo C++

Bạn có thể cho tôi một ví dụ đơn giản về mã đúng không, phương thức ảo của lớp cha sẽ trả về giá trị (nhưng thực thi được cung cấp trong lớp con) và giá trị được trả về bởi phương thức ảo trong lớp cha được sử dụng trong các phương pháp khác của lớp đó. Bởi vì tôi thấy một nơi nào đó (ví dụ ở đây: Safely override C++ virtual functions) rằng điều này có thể gây ra một số vấn đề và phương pháp do người dùng định nghĩa sẽ ghi đè lên phương thức ảo của lớp cha.

Lưu ý: Tôi lập trình bằng Code :: Blocks sử dụng trình biên dịch g ++.

EDIT: theo yêu cầu ở đây một ví dụ đơn giản về những gì tôi muốn:

template<typename T> 
class parent { 
public: 
    // Public methods that user can call 
    int getSomething(T t); 
    void putSomething(T t, int x); 

    // public method that user should implement in his code 
    virtual float compute(T t) { } 

    // protected or private methods and attributes used internally by putSomething ... 
    float doComplexeThings(...); // this can call 
}; 

Phương pháp tính toán() nên được thực hiện bởi người dùng (lớp trẻ). Tuy nhiên, phương thức này() được gọi bởi putSomething() và doComplexeThings() chẳng hạn.

+0

Đối với những gì bạn mô tả, một phương pháp ảo có thể không cần thiết (tính đa hình tĩnh có thể phù hợp với bạn) - khó có thể nói bằng mô tả của bạn. Vui lòng gửi mã mẫu mà bạn đã viết để chúng tôi hiểu rõ hơn về những gì bạn đang cố gắng làm. – kfmfe04

+0

Ví dụ trong câu hỏi được liên kết là về những gì bạn nghĩ là ghi đè nhưng thực sự tuyên bố quá tải do lỗi, ví dụ: một const mất tích và không phải về giá trị trả lại. Bạn nghĩ điều gì là nguy hiểm, chính xác? – CashCow

+0

Trong mã mẫu cổ điển, bạn thậm chí không cần phải khai báo một "tính toán nổi ảo" (T t) '. Bạn chỉ cần sử dụng nó (gọi nó) bên trong putSomething() và doComplexeThings() thông qua 't.compute()', nếu bạn có một xử lý đối với cá thể đó. Trình biên dịch sẽ báo lỗi nếu lớp T của bạn không thực hiện tính toán. Bằng cách này, cha mẹ và T thực sự thậm chí không phải sống trong cùng một hệ thống phân cấp thừa kế: tức là, T là con của mối quan hệ cha mẹ là không bắt buộc. Làm như vậy cũng có thể cung cấp cho bạn một cơ hội để cung cấp cho cha mẹ một tên có ý nghĩa hơn (vì mối quan hệ là không cần thiết). – kfmfe04

Trả lời

18

Bạn chỉ cần đảm bảo rằng các phương thức có cùng chữ ký (bao gồm các biến tố const/mutable và các loại đối số). Bạn có thể sử dụng định nghĩa ảo thuần túy để kích hoạt các lỗi trình biên dịch nếu bạn không ghi đè lên hàm trong một lớp con.

class parent { 
public: 
    // pure virtual method must be provided in subclass 
    virtual void handle_event(int something) = 0; 
}; 

class child : public parent { 
public: 
    virtual void handle_event(int something) { 
    // new exciting code 
    } 
}; 

class incomplete_child : public parent { 
public: 
    virtual void handle_event(int something) const { 
    // does not override the pure virtual method 
    } 
}; 

int main() { 
    parent *p = new child(); 
    p->handle_event(1); // will call child::handle_event 
    parent *p = new incomplete_child(); // will not compile because handle_event 
             // was not correctly overridden 
} 
+0

* Các kiểu trả về Covariant * được phép cho các phương thức ảo. –

+3

@als, chỉ cần một chi tiết nhỏ cho '* loại trả về biến đổi được cho phép *', các loại biến thể chỉ được phép nếu hàm trả về một tham chiếu hoặc con trỏ. Tôi biết rằng bạn biết điều này, nhưng tôi để lại bình luận này cho người khác. –

+2

@mschneider Vấn đề với câu trả lời của bạn là bạn đang buộc phải thay đổi ngữ nghĩa chỉ để tránh một vấn đề tiềm ẩn. Trong trường hợp ban đầu, hàm có mặt nhưng có thể bị quá tải, trong giải pháp đề xuất của bạn, nó * phải * bị quá tải. Điều này không giải quyết được lỗi trong khi quá tải một hàm hiện có, mà đúng hơn là các lớp * bắt nguồn từ quá tải. –

20

Nếu bạn có thể sử dụng C++ 11 tính năng trong trình biên dịch của bạn sau đó sẽ ghi đè có thể được gắn thẻ như vậy với override nhận dạng đặc biệt:

float compute() override; 

Dòng trên trong một lớp học có nguồn gốc sẽ gây ra một trình biên dịch lỗi khi hàm không ghi đè lên hàm thành viên trong cơ sở (chữ ký không chính xác, đối số bị thiếu). Nhưng lưu ý rằng điều này phải được thực hiện trong mỗi lớp dẫn xuất, nó không phải là một giải pháp mà bạn có thể áp đặt từ lớp cơ sở.

Từ lớp cơ sở, bạn chỉ có thể buộc ghi đè bằng cách làm cho hàm thuần ảo, nhưng điều đó sẽ thay đổi ngữ nghĩa. Việc này không tránh các sự cố khi ghi đè, nhưng thay vào đó, buộc ghi đè trong tất cả các trường hợp. Tôi sẽ tránh phương pháp này, và nếu bạn theo dõi nó và có một thực thi hợp lý cho loại cơ sở, hãy thực hiện chức năng ảo cung cấp định nghĩa sao cho việc triển khai các lớp dẫn xuất của bạn chỉ có thể gọi các hàm cơ sở (tức là bạn buộc thực hiện, nhưng trong trường hợp đơn giản nhất, nó sẽ chỉ chuyển tiếp cuộc gọi đến phụ huynh)

+0

+1 cho một tính năng thú vị của C++ 11 - hữu ích để đảm bảo rằng phương pháp của bạn thực sự là ghi đè điều gì đó – kfmfe04

0

Câu hỏi này được hỏi vào năm 2013. Câu hỏi này khá cũ nhưng tôi đã tìm thấy một nội dung mới không tồn tại trong câu trả lời.

Chúng ta cần phải hiểu rõ ba khái niệm này là quá tải, ghi đèẩn.

Câu trả lời ngắn gọn, bạn muốn quá tải hàm kế thừa từ lớp cơ sở. Tuy nhiên, quá tải là cơ chế để thêm nhiều hành vi cho hàm cần tất cả các hàm này theo cùng một tỷ lệ. Nhưng chức năng ảo là trong lớp cơ sở rõ ràng.

class A { 
public: 
    virtual void print() { 
    cout << id_ << std::endl; 
    } 
private: 
    string id_ = "A"; 
}; 

class B : A { 
public: 
    using A::print; 
    void print(string id) { 
    std::cout << id << std::endl; 
    } 
}; 

int main(int argc, char const *argv[]) { 
    /* code */ 
    A a; 
    a.print(); 
    B b; 
    b.print(); 
    b.print("B"); 
    return 0; 
} 

Thêm sử dụng A :: in; trong lớp học lấy được của bạn sẽ làm công việc!

Mặc dù tôi không cảm thấy đó là một ý tưởng tốt kể từ khi triết lý đằng sau quá tảithừa kế là khác nhau, nó có thể không phải là một ý tưởng tốt để làm tổ chúng lại với nhau.

Các vấn đề liên quan