Để hiểu được các mẫu, việc hiểu rõ thuật ngữ một cách thẳng thắn sẽ có lợi rất nhiều vì cách bạn nói về chúng quyết định cách nghĩ về chúng.
Cụ thể, Area
không phải là một lớp mẫu, mà là một mẫu lớp. Đó là, nó là một khuôn mẫu mà từ đó các lớp có thể được tạo ra. Area<int>
là một lớp như vậy (nó không phải là một đối tượng, nhưng tất nhiên bạn có thể tạo một đối tượng từ lớp đó theo cách giống như cách bạn có thể tạo các đối tượng từ bất kỳ lớp nào khác). Một lớp học như vậy sẽ là Area<char>
. Lưu ý rằng đó là các lớp hoàn toàn khác nhau, không có điểm chung nào ngoại trừ việc chúng được tạo từ cùng một mẫu lớp.
Vì Area
không phải là một lớp nên bạn không thể lấy lớp Rectangle
từ nó. Bạn chỉ có thể lấy một lớp từ một lớp khác (hoặc một vài trong số chúng). Vì Area<int>
là một lớp, chẳng hạn, bạn có thể lấy Rectangle
từ nó:
class Rectangle:
public Area<int>
{
// ...
};
Vì Area<int>
và Area<char>
là các lớp khác nhau, bạn thậm chí có thể lấy từ cả hai cùng một lúc (tuy nhiên khi truy cập các thành viên của chúng, bạn sẽ phải đối mặt với sự mơ hồ):
class Rectangle:
public Area<int>,
public Area<char>
{
// ...
};
Tuy nhiên, bạn phải chỉ định được phân loại để lấy từ khi bạn xác định Rectangle
. Điều này đúng cho dù các lớp đó có được tạo từ một khuôn mẫu hay không. Hai đối tượng của cùng một lớp đơn giản không thể có phân cấp kế thừa khác nhau.
Những gì bạn có thể làm là tạo Rectangle
một khuôn mẫu. Nếu bạn viết
template<typename T> class Rectangle:
public Area<T>
{
// ...
};
Bạn có một mẫu Rectangle
mà từ đó bạn có thể lấy một lớp Rectangle<int>
dẫn xuất từ đó Area<int>
và một lớp khác Rectangle<char>
dẫn xuất từ đó Area<char>
.
Có thể bạn muốn có một kiểu duy nhất Rectangle
để bạn có thể chuyển tất cả các loại Rectangle
cho cùng một hàm (bản thân nó không cần biết Kiểu vùng). Vì các Rectangle<T>
lớp được tạo ra bằng cách khởi tạo mẫu Rectangle
là độc lập về mặt hình thức với nhau, nên nó không hoạt động theo cách đó. Tuy nhiên, bạn có thể sử dụng đa kế thừa tại đây:
class Rectangle // not inheriting from any Area type
{
// Area independent interface
};
template<typename T> class SpecificRectangle:
public Rectangle,
public Area<T>
{
// Area dependent stuff
};
void foo(Rectangle&); // A function which works with generic rectangles
int main()
{
SpecificRectangle<int> intrect;
foo(intrect);
SpecificRectangle<char> charrect;
foo(charrect);
}
Nếu điều quan trọng là giá trị chung của bạn Rectangle
có nguồn gốc từ chung, Area
bạn cũng có thể thực hiện thủ thuật tương tự Area
:
class Area
{
// generic Area interface
};
class Rectangle:
public virtual Area // virtual because of "diamond inheritance"
{
// generic rectangle interface
};
template<typename T> class SpecificArea:
public virtual Area
{
// specific implementation of Area for type T
};
template<typename T> class SpecificRectangle:
public Rectangle, // maybe this should be virtual as well, in case the hierarchy is extended later
public SpecificArea<T> // no virtual inheritance needed here
{
// specific implementation of Rectangle for type T
};