2012-01-09 32 views
11

Trong mẫu:C++ lớp mẫu chuyên môn: tại sao phương pháp phổ biến cần phải được tái thực hiện

#include <iostream> 

using namespace std; 

class B 
{ 
public: 
    virtual void pvf() = 0; 
}; 

template <class T> 
class D : public B 
{ 
public: 
    D(){} 

    virtual void pvf() {} 

private: 
    string data; 
}; 

template <> 
class D<bool> : public B 
{ 
public: 
    D(); 

    virtual void pvf(){ cout << "bool type" << endl; } 
}; 

int main() 
{ 
    D<int> d1; 
    D<bool> d2; 
} 

tôi nhận được lỗi sau:

test.cpp:(.text+0x1c): undefined reference to `D<bool>::D()' 

Lưu ý rằng lý do tôi don' t chỉ chuyên D() của chính nó là tôi muốn loại bỏ sự cần thiết cho chuỗi D<T>::data trong trường hợp D<bool>.

Tại sao tôi cần phải triển khai lại D() trong D<bool>? Có vẻ như có một cách để tôi nói cho trình biên dịch sử dụng phiên bản từ D<T>.

Có cách nào để thực hiện một chuyên môn đơn giản như thế này mà không phải triển khai lại các phương pháp không?

+0

Vì đây là một loại hoàn toàn mới. –

Trả lời

10

Không, không có.

Chuyên môn hoạt động rất khác so với kế thừa. Nó không có kết nối với phiên bản mẫu chung.

Khi bạn sử dụng/tạo mẫu, trình biên dịch sẽ tạo tên loại mới và sau đó tìm cách xác định loại này. Khi nó tìm thấy một chuyên môn, sau đó nó có nghĩa là định nghĩa cho loại mới. Khi không, nó lấy mẫu chung và khởi tạo nó.

Vì vậy chúng không có kết nối, và bạn chỉ đang viết một lớp hoàn toàn mới, chỉ với một tên đặc biệt cho trình biên dịch tìm trong trường hợp ai đó sử dụng/instantiating mẫu để tìm nó dưới tên đó.

+7

Đó là điều không may – Jaime

1

Bạn cần triển khai lại vì D<T>D<bool> là các lớp hoàn toàn không liên quan (chúng chỉ xảy ra với "chia sẻ tên"). Đó chỉ là cách các mẫu hoạt động.

Nếu bạn muốn các lớp học chia sẻ mã xây dựng, chỉ cần đặt mã đó vào bên trong B::B (tức là điều bạn làm mỗi khi bạn muốn sử dụng lại mã trong các nhánh khác nhau của cùng một hệ thống phân cấp: di chuyển mã lên và để tay cầm kế thừa phần còn lại).

12

Mỗi chuyên môn của một mẫu lớp cho một lớp khác nhau - chúng không chia sẻ bất kỳ thành viên nào với nhau. Vì bạn đã chuyên môn hóa toàn bộ lớp, bạn không nhận được bất kỳ thành viên nào từ mẫu và phải triển khai tất cả chúng.

Bạn có thể chuyên một cách rõ ràng các thành viên cá nhân, chứ không phải là toàn bộ lớp:

template <> void D<bool>::pvf(){ cout << "bool type" << endl; } 

Sau đó D<bool> vẫn sẽ chứa tất cả các thành viên của lớp mẫu mà bạn chưa rõ ràng chuyên ngành, bao gồm cả các nhà xây dựng mặc định.

+0

Đánh bại tôi với nó bằng 21 giây (nhưng chỉ vì tôi phải kiểm tra điều này để chắc chắn rằng nó có thể :)) +1 –

+0

Tôi biết bạn có thể chuyên phương pháp, đó là lý do tại sao tôi đưa vào lưu ý về lý do tại sao tôi ' m không làm điều đó ... Mục tiêu của tôi là có một thành viên dữ liệu trong một nhưng không phải là thành viên khác và không phải thực hiện lại các phương pháp phổ biến. Tôi hiểu những gì đang xảy ra, chỉ không hiểu tại sao phương pháp chung không thể được sử dụng lại. – Jaime

4

Vấn đề là giả định sai lầm của mình rằng có bất cứ điều gì chung giữa D<A>D<B>. Các phiên bản mẫu là loại và hai phiên bản khác nhau là hai loại khác nhau, kết thúc của câu chuyện. Điều này chỉ xảy ra khi các mẫu cùng mẫu có mã tương tự về mặt chính thức, nhưng với chuyên môn, bạn có thể xác định bất kỳ loại nào bạn thích.Tóm lại, mọi loại mà bạn xác định rõ ràng là hoàn toàn độc lập và không có sự phổ biến nào trong các trường hợp mẫu chuyên biệt, ngay cả khi chúng có cùng tên.

Ví dụ:

template <typename T> struct Foo 
{ 
    T & r; 
    const T t; 
    void gobble(const T &); 
    Foo(T *); 
}; 

template <> struct Foo<int> 
{ 
    std::vector<char> data; 
    int gobble() const; 
    Foo(bool, int, Foo<char> &); 
}; 

Các loại Foo<char>Foo<int> không có gì để làm với nhau, và không có lý do tại sao bất kỳ phần nào của một nên có bất kỳ sử dụng bên trong khác.

Nếu bạn muốn yếu tố ra các tính năng thông thường, sử dụng thừa kế riêng:

template <typename> struct D : private DImpl { /* ... */ } 
+0

Ngừng lấy suy nghĩ của tôi và hình thành chúng như là câu trả lời của bạn! :( – Xeo

+0

@Xeo: Đặt trên nắp thiếc của bạn sau đó –

+0

Không đưa ra bất kỳ giả định nào, chỉ cần tự hỏi tại sao tôi không thể yêu cầu trình biên dịch sử dụng việc triển khai mặc định cho mẫu. Tôi hiểu mọi loại mẫu là một loại khác nhau bất kể chuyên môn Nếu trình biên dịch có thể sử dụng cùng một phương pháp cho cả hai loại, tại sao không cho một chuyên môn miễn là không có xung đột – Jaime

0

Hãy xem xét rằng D<T>::D() sẽ chịu trách nhiệm mặc định-xây dựng string data, và rằng D<bool> không có bất kỳ thành viên đó. Rõ ràng không có cách nào để sử dụng cùng một mã được phát ra trong mỗi trường hợp.

Tuy nhiên, nếu nhà xây dựng mặc định của bạn không làm bất cứ điều gì (trong hoặc phiên bản tại đây), chỉ cần bỏ qua nó và cho phép trình biên dịch thực hiện công việc.

+0

Cùng một vấn đề với phương thức khác với hàm tạo. – Jaime

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