2010-04-16 71 views
7

Tôi muốn chuyển tiếp khai báo một hàm thành viên tĩnh của một lớp trong tệp khác. Những gì tôi muốn làm trông như thế này:chuyển tiếp khai báo hàm tĩnh C++

BigMassiveHeader.h:

class foo 
{ 
    static void init_foos(); 
} 

main.cpp:

class foo; 
void foo::init_foos(); 
int main(char** argv, int argc) 
{ 
    foo::init_foos() 
} 

này thất bại với "lỗi C2027: sử dụng các loại không xác định 'foo' "

Có cách nào để thực hiện những gì tôi muốn làm với việc làm init_foos một chức năng miễn phí, hoặc bao gồm BigMassiveHeader.h? (BigMassiveHeader.h là thời gian biên dịch đáng chú ý, và được bao gồm ở mọi nơi.)

+0

Cho dù để bao gồm mã trong các .cpp hoặc trong BigHeader.h không nên có hiệu lực. Sau khi tất cả, bạn đang sử dụng #include bảo vệ hoặC#pragma một lần vì vậy BigHeader.h chỉ được biên dịch một lần, phải không? – Kyte

+2

@Kyte Bao gồm các nhân viên bảo vệ giới hạn BigHeader.h một lần cho mỗi đơn vị dịch mà nó được bao gồm. Nếu nó đang được bao gồm trong nhiều tập tin nguồn, nó sẽ cần phải được biên dịch nhiều lần. – KeithB

+0

Vì vậy, nó sẽ có thể tách ra định nghĩa của 'lớp foo' vào một tập tin tiêu đề? –

Trả lời

10

Bạn không thể chuyển tiếp khai báo thành viên của một lớp, bất kể họ có tĩnh hay không.

+0

Nó thậm chí không phải là một khai báo chuyển tiếp của 'foo :: init_foos();', mà đúng hơn là một khai báo của một hàm toàn cầu có tên là 'init_foos()'. –

+6

Nói đúng ra, cách nói C++ không có thuật ngữ như "khai báo chuyển tiếp". Nói chung, "tuyên bố chuyển tiếp" thường có nghĩa là "khai báo mà không xác định". Tính đến điều này, có thể "chuyển tiếp khai báo" một hàm thành viên. Mỗi khi bạn * định nghĩa * một lớp, bạn đang "chuyển tiếp khai báo" các hàm thành viên [không nội tuyến] của nó. Câu trả lời đúng là: bạn không thể * khai báo * một thành viên của lớp mà không có * định nghĩa * lớp đó. Câu trả lời đã bị xóa của James McNellis thực sự là một câu trả lời chính xác. – AnT

+2

@AndreyT: Phần Chuẩn 27.2 có tiêu đề "Tuyên bố chuyển tiếp" và có mục nhập chỉ mục trong phiên bản đặc biệt của TC++ PL. –

0

Không, bạn cần bao gồm tiêu đề cho điều đó. Lấy làm tiếc.

Sử dụng chức năng miễn phí nếu bạn phải hoặc chia lớp.

4

Bạn không thể chuyển tiếp khai báo thành viên trong lớp của mình nhưng bạn có thể tạo vùng tên và hàm bên trong không gian tên đó và chuyển tiếp khai báo.

namespace nsfoo 
{ 
    void init_foos(); 
} 

Lớp học của bạn nếu cần thiết có thể kết bạn với chức năng này.

2

Nếu bạn có số BigMassiveHeader, bạn nên xem xét tách nó thành nhiều số SmallCompactHeaders. Nếu bạn muốn thể hiện rằng nhiều lớp và hàm thuộc về ngữ nghĩa, bạn có thể đặt chúng trong cùng một không gian tên. Bạn luôn có thể cung cấp tiêu đề tiện lợi bao gồm tất cả các tiêu đề nhỏ của bạn.

+0

Chúng tôi biết rõ điều này. Việc tái cấu trúc BigMassiveHeader là một khoản nợ kỹ thuật mà chúng tôi thừa kế từ những người tiền nhiệm và đang trả góp. Điều này, trên thực tế là sự lo lắng của nỗ lực đó. –

0

Tôi biết nó không phải là điểm của câu hỏi, nhưng nếu BigMassiveHeader.h là không có khả năng thay đổi nhiều theo thời gian, bạn nên có một cái nhìn tại precompiled headers

0

Là một refactoring đầu tiên, tôi muốn sử dụng miễn phí hàm gọi hàm tĩnh. Nó không giống như phương pháp chính của bạn là nhận được gọi là rất nhiều lần, vì vậy bạn sẽ không nhận thấy một cuộc gọi thêm, và điều đó làm cho ít nhất là thay đổi mã hiện có.

Tất nhiên, bạn không thực sự nói những gì bạn đang cố gắng làm, chỉ những gì bạn muốn làm. Nếu những gì bạn đang cố gắng làm là nhận được được gọi một lần khi bắt đầu ứng dụng, hãy sử dụng khởi tạo đối tượng tĩnh cho điều đó, thay vì gọi nó trong chính. Nếu những gì bạn đang cố gắng làm là lấy được gọi sau khi tất cả các đối tượng tĩnh được tạo ra, thì nó phức tạp hơn.

Bằng cách khởi tạo đối tượng tĩnh, tôi muốn nói điều gì đó giống như việc này trong tệp .cpp có quyền truy cập vào định nghĩa của .Làm cho nó một người bạn và tin để ngăn chặn nhiều cuộc gọi:

struct call_init_foos { 
    call_init_foos() { foo::init_foos(); } 
} call_init_foos_on_startup; 
0

để chuyển tiếp tuyên bố một phương pháp duy nhất của một lớp, bạn phải khai báo phương pháp này như là một phần của lớp (vì nó thực sự là).

ví dụ, trong trường hợp của bạn, thêm vào main.cpp:

class foo 
{ 
public: 
    static void init_foos(); 
} 

của nó không phải là đẹp nhất, nhưng nó sẽ giúp bạn tiết kiệm phải bao gồm toàn bộ tiêu đề ..

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