Để 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ể, Areakhô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ì Areakhông phải là một lớp nên bạn không thể lấy lớp Rectangletừ 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 Rectangletừ 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 Rectanglemộ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 Rectanglemà 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 Rectanglecho 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 Rectanglelà độ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 Rectanglecó nguồn gốc từ chung, Areabạ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
};