使用模板继承钻石时会出错吗?
Can I make error when diamond inheritance with template?
我想在重复继承时出错。这是我找到它的方式。
#include <utility>
class Person {};
class Man : public Person {};
class Woman : public Person {};
template <typename... Types>
class merge_class : public Types... {};
template <typename... Types>
struct condition
{
using merge = merge_class<Types...>;
using type = std::enable_if<
std::is_convertible<merge, Person>::value // condition
, merge>::type;
};
class BummooKim : public condition<Man>::type {};
class Daniel : public condition<Woman>::type {};
//class Unkown : public condition<Man, Woman>::type {}; // There is an error in the declaration.
但是,我发现如果有非默认构造函数,这种方式就不能使用了。
想知道有没有关键字表示必须单继承
如果c++不支持'keyword',我想要另一种方式。
例子
class OtherWay : public condition<Man, Other>::type
{
OtherWay() : Man() {}
};
你 运行 进入的是所谓的菱形继承 (https://www.makeuseof.com/what-is-diamond-problem-in-cpp/),除了“接口”之外,最好避免使用 IMO。我更喜欢使用实现的组合,也称为混合模式(它又使用 CRTP,即奇怪的递归模板模式)。在这种模式中,您可以实现不同的功能(例如,在下面的示例中,男人可以大喊,女人可以微笑,所有人都可以打招呼。)。
在编译时检测多重继承是不可能的(c++ 中可能启用它的功能从未通过标准委员会)。
我展示了一种至少可以在编译时检测到一个人不能同时是男人和女人的方法(至少在这个例子中是这样)。
在 MSVC 中,此程序会出现以下编译错误:
错误 C2338 既是男人又是女人,在这个程序中是不正确的
#include <iostream>
#include <string>
//-----------------------------------------------------------------------------
// multiple inheritance from interfaces (abstract base classes is fine)
// class to introduce a concept of an interface
// and set all the constructors/destructors default behavior.
class Interface
{
public:
virtual ~Interface() = default;
protected:
Interface() = default; // protected constructor, avoids accidental instantiation
};
//-----------------------------------------------------------------------------
// for each aspect/capability of a person define a seperate interface
// this will also allow client code to cast an object to either of those
// interfaces to check if functionality is available
class PersonItf :
public Interface
{
public:
virtual void SayHi() const = 0;
};
//-----------------------------------------------------------------------------
// A man can shout
class ManItf :
public Interface
{
public:
virtual void Shout() const = 0;
};
//-----------------------------------------------------------------------------
// A woman can smile
class WomanItf :
public Interface
{
public:
virtual void Smile() const = 0;
};
//-----------------------------------------------------------------------------
// mixin classes for reusable code
template<typename base_t>
class PersonImpl :
public PersonItf
{
public:
void SayHi() const override
{
std::cout << "Hi!\n";
}
};
template<typename base_t>
class ManImpl :
public ManItf
{
public:
void Shout() const override
{
std::cout << "Yohoohoooo!\n";
};
};
template<typename base_t>
class WomanImpl:
public WomanItf
{
public:
void Smile() const override
{
std::cout << "Smile!\n";
};
};
//-----------------------------------------------------------------------------
// now we can group capabilities together in classes
//
class Man :
public ManImpl<Man>
{
};
class Woman :
public WomanImpl<Woman>
{
};
class ManAndWoman :
public ManImpl<ManAndWoman>,
public WomanImpl<ManAndWoman>
{
};
//-----------------------------------------------------------------------------
// this Person class will check validity of the composition
// at compile time.
template<typename type_t>
struct Person :
public PersonImpl<type_t>,
public type_t
{
static_assert(!(std::is_base_of_v<WomanItf, type_t>&& std::is_base_of_v<ManItf, type_t>), "Being both a Man and a Woman is not correct in this program\n");
};
//-----------------------------------------------------------------------------
class Daniel : public Person<ManAndWoman> {};
class Santa : public Person<Man> {};
int main()
{
Daniel daniel;
Santa santa;
daniel.SayHi();
santa.Shout();
return 0;
}
定义
#include <utility>
namespace Definer
{
// define
namespace Classification
{
class Person { unsigned int age; };
}
class Man : public Classification::Person {};
class Woman : public Classification::Person {};
// conditions
template <typename Derived>
static constexpr bool is_convertible_person()
{
constexpr bool result = std::is_convertible<Derived, Classification::Person>::value;
static_assert(result, "Person is duplicated.");
return result;
}
template <typename Derived>
concept Condition
= is_convertible_person<Derived>();
}
如何通过继承使其成为可能
namespace Definer
{
template <typename Derived>
requires Condition<Derived>
class Requires
{};
}
class Daniel :
public Definer::Man,
public Definer::Requires<Daniel> // Not require, but similar
{};
比较 class 尺寸。并出错。
class Compare :
public Definer::Man
{};
constexpr size_t size_of_Daniel = sizeof(Daniel); // 4U
constexpr size_t size_of_Compare = sizeof(Compare); // 4U
// This class make an error well, except for repeated occurrences.
class Santa :
public Definer::Man,
public Definer::Woman,
public Definer::Requires<Santa> // Not require, but similar
{};
//class Desire :
// public Definer::Man
// requires Definer::Condition<Desire> // It is not support now. I don't know if it will be possible later.
// 2021.12.20 c++20 preview
//{};
我想在重复继承时出错。这是我找到它的方式。
#include <utility>
class Person {};
class Man : public Person {};
class Woman : public Person {};
template <typename... Types>
class merge_class : public Types... {};
template <typename... Types>
struct condition
{
using merge = merge_class<Types...>;
using type = std::enable_if<
std::is_convertible<merge, Person>::value // condition
, merge>::type;
};
class BummooKim : public condition<Man>::type {};
class Daniel : public condition<Woman>::type {};
//class Unkown : public condition<Man, Woman>::type {}; // There is an error in the declaration.
但是,我发现如果有非默认构造函数,这种方式就不能使用了。
想知道有没有关键字表示必须单继承
如果c++不支持'keyword',我想要另一种方式。
例子
class OtherWay : public condition<Man, Other>::type
{
OtherWay() : Man() {}
};
你 运行 进入的是所谓的菱形继承 (https://www.makeuseof.com/what-is-diamond-problem-in-cpp/),除了“接口”之外,最好避免使用 IMO。我更喜欢使用实现的组合,也称为混合模式(它又使用 CRTP,即奇怪的递归模板模式)。在这种模式中,您可以实现不同的功能(例如,在下面的示例中,男人可以大喊,女人可以微笑,所有人都可以打招呼。)。
在编译时检测多重继承是不可能的(c++ 中可能启用它的功能从未通过标准委员会)。
我展示了一种至少可以在编译时检测到一个人不能同时是男人和女人的方法(至少在这个例子中是这样)。
在 MSVC 中,此程序会出现以下编译错误:
错误 C2338 既是男人又是女人,在这个程序中是不正确的
#include <iostream>
#include <string>
//-----------------------------------------------------------------------------
// multiple inheritance from interfaces (abstract base classes is fine)
// class to introduce a concept of an interface
// and set all the constructors/destructors default behavior.
class Interface
{
public:
virtual ~Interface() = default;
protected:
Interface() = default; // protected constructor, avoids accidental instantiation
};
//-----------------------------------------------------------------------------
// for each aspect/capability of a person define a seperate interface
// this will also allow client code to cast an object to either of those
// interfaces to check if functionality is available
class PersonItf :
public Interface
{
public:
virtual void SayHi() const = 0;
};
//-----------------------------------------------------------------------------
// A man can shout
class ManItf :
public Interface
{
public:
virtual void Shout() const = 0;
};
//-----------------------------------------------------------------------------
// A woman can smile
class WomanItf :
public Interface
{
public:
virtual void Smile() const = 0;
};
//-----------------------------------------------------------------------------
// mixin classes for reusable code
template<typename base_t>
class PersonImpl :
public PersonItf
{
public:
void SayHi() const override
{
std::cout << "Hi!\n";
}
};
template<typename base_t>
class ManImpl :
public ManItf
{
public:
void Shout() const override
{
std::cout << "Yohoohoooo!\n";
};
};
template<typename base_t>
class WomanImpl:
public WomanItf
{
public:
void Smile() const override
{
std::cout << "Smile!\n";
};
};
//-----------------------------------------------------------------------------
// now we can group capabilities together in classes
//
class Man :
public ManImpl<Man>
{
};
class Woman :
public WomanImpl<Woman>
{
};
class ManAndWoman :
public ManImpl<ManAndWoman>,
public WomanImpl<ManAndWoman>
{
};
//-----------------------------------------------------------------------------
// this Person class will check validity of the composition
// at compile time.
template<typename type_t>
struct Person :
public PersonImpl<type_t>,
public type_t
{
static_assert(!(std::is_base_of_v<WomanItf, type_t>&& std::is_base_of_v<ManItf, type_t>), "Being both a Man and a Woman is not correct in this program\n");
};
//-----------------------------------------------------------------------------
class Daniel : public Person<ManAndWoman> {};
class Santa : public Person<Man> {};
int main()
{
Daniel daniel;
Santa santa;
daniel.SayHi();
santa.Shout();
return 0;
}
定义
#include <utility>
namespace Definer
{
// define
namespace Classification
{
class Person { unsigned int age; };
}
class Man : public Classification::Person {};
class Woman : public Classification::Person {};
// conditions
template <typename Derived>
static constexpr bool is_convertible_person()
{
constexpr bool result = std::is_convertible<Derived, Classification::Person>::value;
static_assert(result, "Person is duplicated.");
return result;
}
template <typename Derived>
concept Condition
= is_convertible_person<Derived>();
}
如何通过继承使其成为可能
namespace Definer
{
template <typename Derived>
requires Condition<Derived>
class Requires
{};
}
class Daniel :
public Definer::Man,
public Definer::Requires<Daniel> // Not require, but similar
{};
比较 class 尺寸。并出错。
class Compare :
public Definer::Man
{};
constexpr size_t size_of_Daniel = sizeof(Daniel); // 4U
constexpr size_t size_of_Compare = sizeof(Compare); // 4U
// This class make an error well, except for repeated occurrences.
class Santa :
public Definer::Man,
public Definer::Woman,
public Definer::Requires<Santa> // Not require, but similar
{};
//class Desire :
// public Definer::Man
// requires Definer::Condition<Desire> // It is not support now. I don't know if it will be possible later.
// 2021.12.20 c++20 preview
//{};