2010-07-10 16 views
9

Tôi có một lớp cơ sở khai báo và định nghĩa một constructor, nhưng đối với một số lý do của tôi công khai nguồn gốc lớp không nhìn thấy constructor đó, và do đó tôi phải khai báo rõ ràng một constructor chuyển tiếp trong lớp có nguồn gốc:Tại sao lớp con C++ của tôi cần một hàm tạo rõ ràng?

class WireCount0 { 
protected: 
    int m; 
public: 
    WireCount0(const int& rhs) { m = rhs; } 
}; 

class WireCount1 : public WireCount0 {}; 

class WireCount2 : public WireCount0 { 
public: 
    WireCount2(const int& rhs) : WireCount0(rhs) {} 
}; 

int dummy(int argc, char* argv[]) { 
    WireCount0 wireCount0(100); 
    WireCount1 wireCount1(100); 
    WireCount2 wireCount2(100); 
    return 0; 
} 

Trong đoạn mã trên, khai báo WireCount1 wireCount1(100) của tôi bị từ chối bởi trình biên dịch ("Không có hàm phù hợp cho cuộc gọi đến" WireCount1 :: WireCount1 (int) '"), trong khi các khai báo wireCount0wireCount2 của chúng tôi là tốt.

Tôi không chắc chắn rằng tôi hiểu tại sao tôi cần phải cung cấp hàm tạo rõ ràng được hiển thị trong WireCount2. Có phải vì trình biên dịch tạo ra một hàm tạo mặc định cho WireCount1 và hàm tạo đó ẩn trình xây dựng WireCount0?

Để tham khảo, trình biên dịch là i686-apple-darwin10-gcc-4.2.1 (GCC) 4.2.1 (Apple Inc. build 5659).

Trả lời

4

Tất cả các lớp dẫn xuất phải gọi hàm tạo của lớp cơ sở của chúng trong một số hình dạng hoặc biểu mẫu.

Khi bạn tạo một hàm tạo quá tải, trình biên dịch mặc định của bạn đã tạo ra hàm tạo tham số biến mất và các lớp dẫn xuất phải gọi hàm tạo quá tải.

Khi bạn có một cái gì đó như thế này:

class Class0 { 
} 

class Class1 : public Class0 { 
} 

Trình biên dịch thực sự tạo này:

class Class0 { 
public: 
    Class0(){} 
} 

class Class1 : public Class0 { 
    Class1() : Class0(){} 
} 

Khi bạn có constructor không mặc định, các nhà xây dựng parameterless không còn được tạo ra. Khi bạn xác định như sau:

class Class0 { 
public: 
    Class0(int param){} 
} 

class Class1 : public Class0 { 
} 

Trình biên dịch không còn tạo ra một constructor trong Class1 để gọi constructor lớp cơ sở, bạn dứt khoát phải làm điều đó cho mình.

+0

Tôi nghĩ bạn đã hiểu sai câu hỏi của mình. Anh ta không hỏi tại sao anh ta không thể gọi constructor mặc định của Class1, nhưng đúng hơn là tại sao không có constructor Class1 (int) nào để gọi. – Shirik

+1

Trình biên dịch vẫn tạo ra một hàm tạo 'Class1()' trong ví dụ cuối cùng của bạn. Nó chỉ là constructor này là ill-hình thành nếu nó thực sự được xác định (theo mặc định như cho tất cả các chức năng đặc biệt, nó chỉ tuyên bố cho đến khi nó thực sự được sử dụng).Bạn có thể xác minh điều này bằng cách làm cho nó trở thành một người bạn: 'class Class2 {friend Class1 :: Class1(); }; ', hoạt động vì trình biên dịch ngầm khai báo constructor mặc định cho dù nó có thực sự được gọi hay không. –

+0

Cảm ơn. Điều đó làm cho nó rất rõ ràng với tôi. Mặc dù tôi đánh giá cao phản ứng của Shirik, tôi tin rằng ví dụ của bạn cho thấy chính xác những gì đang xảy ra trong mã của tôi. –

14

Các nhà xây dựng không được kế thừa. Bạn phải tạo một hàm tạo cho lớp dẫn xuất. Phương thức khởi tạo của lớp dẫn xuất, hơn nữa, phải gọi hàm tạo của lớp cơ sở.

+1

Ngoài ra, nếu lớp cơ sở có hàm khởi tạo mặc định thì trình biên dịch sẽ sử dụng trình tạo đó nếu bạn không chỉ định rõ ràng một hàm tạo trong danh sách khởi tạo của một hàm tạo trong lớp dẫn xuất. –

+0

Cảm ơn. Tôi đã không nhận ra rằng các nhà thầu không bao giờ được kế thừa. Tôi đã thuyết phục bản thân rằng các nhà xây dựng lớp cơ sở khác (trong mã thực) đã có thể nhìn thấy được, nhưng bây giờ tôi đã gán nó cho một bó mà trình biên dịch có thể đang làm. –

+0

Tôi rất tiếc là một người mới, tôi chưa có đủ điểm danh tiếng để làm nổi bật câu trả lời của bạn. –

1

Bạn phải xây dựng lớp cơ sở của mình trước khi giao dịch với nguồn gốc. Nếu bạn xây dựng lớp dẫn xuất của bạn với các nhà xây dựng không tầm thường, trình biên dịch không thể quyết định những gì để gọi cho cơ sở, đó là lý do tại sao lỗi xảy ra.

+0

Một câu trả lời đúng khác. Cảm ơn bạn. –