Jest to możliwe do sprawdzenia w czasie kompilacji. Kluczem jest to, że jeśli mamy wzór diamentowe:

można jednoznacznie oddania D&
do A&
. Jednakże, jeśli nie jest dziedziczenie wirtualne:

obsada będzie niejednoznaczna. Więc spróbujmy zrobić diament!
template <typename Base, typename Derived>
class make_diamond {
struct D2 : virtual Base { }; // this one MUST be virtual
// otherwise we'd NEVER have a diamond
public:
struct type : Derived, D2 { };
};
W tym momencie jest to po prostu kolejna cecha void_t
typ -Style:
template <typename Base, typename Derived, typename = void>
struct is_virtual_base_of : std::false_type { };
template <typename Base, typename Derived>
struct is_virtual_base_of<Base, Derived, void_t<
decltype(static_cast<Base&>(
std::declval<typename make_diamond<Base, Derived>::type&>()))
>> : std::true_type { };
Jeśli obsada jest jednoznaczne wyrażenie w częściowej specjalizacji będzie ważna i że specjalizacja będzie korzystny. Jeśli obsada jest niejednoznaczna, wystąpi awaria substytucji, a kończy się podstawową. Zauważ, że Base
tutaj faktycznie nie trzeba mieć żadnych funkcji virtual
członków:
struct A { };
struct B : public A { };
struct C : virtual A { };
std::cout << is_virtual_base_of<A, B>::value << std::endl; // 0
std::cout << is_virtual_base_of<A, C>::value << std::endl; // 1
A jeśli ma żadnych czystych funkcji składowych wirtualnych, nie trzeba ich zastąpić ponieważ nigdy nie faktycznie budowy obiektu .
struct A2 { virtual void foo() = 0; };
struct B2 : public A2 { void foo() override { } };
struct C2 : virtual A2 { void foo() override { } };
std::cout << is_virtual_base_of<A2, B2>::value << std::endl; // 0
std::cout << is_virtual_base_of<A2, C2>::value << std::endl; // 1
Oczywiście jeśli klasa jest oznaczony final
, to nie będzie działać w ogóle. Ale wtedy, gdyby było to final
, nie miałoby znaczenia, jaki rodzaj dziedzictwa miał w ogóle.
Możliwe, że można to teraz zrobić lepiej, ale w VS2010 istnieje słowo kluczowe o nazwie "__interface" firmy Microsoft. Jednak jest to a) nie jest przenośne i b) Musisz być ostrożny, ponieważ z jakiegoś powodu te interfejsy nie mogą mieć wirtualnego destruktora. – Excelcius
To brzmi bardziej jak specyfikacja techniczna niż wymaganie funkcjonalne. Dlaczego tego potrzebujesz? –
@Excelcius Pracujemy dla systemu Linux i Windows; Wymieniłem VS2010, ponieważ gcc wyprzedza wsparcie C++ 11. – Angew