2012-06-27 32 views
5

Tôi có một lớp cơ sở trừu tượng và muốn thực hiện một hàm trong lớp dẫn xuất. Tại sao tôi lại phải khai báo hàm trong lớp dẫn xuất?Tại sao giao diện cần phải được redeclared?

class base { 
public: 
    virtual int foo(int) const = 0; 
}; 

class derived : public base { 
public: 
    int foo(int) const; // Why is this required? 
}; 

int derived::foo(int val) const { return 2*val; } 

Trả lời

7

Hãy xem xét định nghĩa lớp dẫn xuất có thể nằm trong tiêu đề, trong khi việc triển khai có thể nằm trong tệp nguồn. Tiêu đề thường được đưa vào nhiều vị trí ("đơn vị dịch"), mỗi phần sẽ được biên dịch độc lập. Nếu bạn không khai báo ghi đè, thì trình biên dịch sẽ không biết về nó trong bất kỳ đơn vị dịch nào khác.

+0

Điều này có nghĩa là, nếu tôi không redeclare chức năng trong lớp dẫn xuất trình biên dịch sẽ không tìm kiếm việc thực hiện ghi đè của lớp dẫn xuất? – Michael

+0

@Michael: Vâng, tôi nghĩ đó là chính xác. –

4

Mục đích thực hiện một chức năng tinh khiết virtual trong lớp cơ sở là các lớp có nguồn gốc phải ghi đè lên nó và cung cấp thực hiện riêng của mình.
Lưu ý rằng sự hiện diện của hàm ảo thuần túy trong lớp khiến lớp đó là Abstract class. Nói một cách đơn giản, lớp này hoạt động như một giao diện để tạo các lớp cụ thể hơn. Không thể tạo các đối tượng của lớp Abstract.

Nếu bạn không ghi đè hàm ảo thuần túy trong lớp dẫn xuất thì lớp dẫn xuất chỉ chứa lớp cơ sở thuần thuần túy được thừa kế và nó cũng hoạt động như một lớp trừu tượng. Khi lớp dẫn xuất của bạn trừu tượng, nó không thể được khởi tạo.
Vì vậy, để lớp dẫn xuất của bạn được khởi tạo, nó cần ghi đè và do đó khai báo hàm ảo thuần túy.

+0

Bạn nói đúng. Tuy nhiên, ngay cả khi lớp cơ sở không trừu tượng, tôi cần phải redeclare chức năng nếu tôi muốn ghi đè lên việc thực hiện. – Michael

1

It is to override the abstraction of the base class.

Nếu bạn không khai báo lại, thì lớp dẫn xuất của bạn cũng là lớp trừu tượng. Nếu bạn làm như vậy bạn bây giờ có một loại không trừu tượng của cơ sở.

2

Bạn có thể nghĩ rằng trình biên dịch có thể suy ra rằng bạn sẽ phải cung cấp một thực hiện derived::foo(), nhưng derived cũng có thể là một lớp trừu tượng (và trong thực tế đó là những gì bạn sẽ nhận được nếu bạn không khai báo foo() trong derived)

1

Do cấu trúc phân cấp có thể có nhiều lớp hơn.

struct Base { 
    virtual void foo() const = 0; 
    virtual void bar() const = 0; 
}; 

struct SuperBase: Base { 
    virtual void bar() const override; 
}; 

struct Concrete: SuperBase { 
    virtual void foo() const override; 
}; 

Ở đây, SuperBase không cung cấp một thực hiện cho foo, điều này cần được chỉ ra bằng cách nào đó.

1

Trong khi bạn không thể nhanh chóng một lớp học với khái niệm hàm ảo thuần túy, bạn vẫn có thể tạo ra một lớp như thế này:

class base { 
public: 
    virtual int foo(int) const = 0; 
}; 

class derived : public base { 
public: 
}; 

class very_derived : public derived { 
public: 
    virtual int foo(int) const { return 2; } 
}; 

Các lớp có nguồn gốc vẫn là một lớp trừu tượng, nó không thể được khởi tạo vì nó không ghi đè foo. Bạn cần khai báo một phiên bản foo ảo không thuần khiết trước khi bạn có thể khởi tạo lớp, ngay cả khi bạn không định nghĩa foo ngay lập tức.

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