C++ 从派生类中引用基类的更好习惯用法?
假设我有一个C++ 从派生类中引用基类的更好习惯用法?,c++,inheritance,self-reference,idioms,C++,Inheritance,Self Reference,Idioms,假设我有一个 template <typename T> class A : class_with_long_name<T, and_many_other, template_arguments, oh_my_thats_long>, anotherclass_with_long_name<and_many_other, template_arguments_that, are_also_annoying, including_also, T>
template <typename T>
class A :
class_with_long_name<T, and_many_other, template_arguments, oh_my_thats_long>,
anotherclass_with_long_name<and_many_other, template_arguments_that, are_also_annoying, including_also, T> { ... }
模板
A类:
具有长名称的类,
另一个类名为{…}
现在,在类A的定义和/或其方法中,我需要引用两个超类(例如,访问超类中的成员,或其中定义的类型等),但是,我希望避免重复超类名称。目前,我正在做的是:
template<typename T>
class A :
class_with_long_name<T, and_many_other, template_arguments, oh_my_thats_long>,
anotherclass_with_long_name<and_many_other, template_arguments_that, are_also_annoying, including_also, T>
{
using parent1 = class_with_long_name<T, and_many_other, template_arguments, oh_my_thats_long>;
using parent2 = anotherclass_with_long_name<and_many_other, template_arguments_that, are_also_annoying, including_also, T>;
...
}
模板
A类:
具有长名称的类,
另一个名为“long”的类
{
使用parent1=class_和_long_名称;
使用parent2=另一个具有长名称的类;
...
}
这显然有效,并将重复次数减少到2次;但如果可能的话,我宁愿避免这种重复。有没有一个合理的方法来做到这一点
注:
- “合理”,例如,没有宏,除非有非常好的理由
- 在A之前,您可以
namespace detail
{
template <typename T>
using parentA1 = class_with_long_name<T,
and_many_other,
template_arguments,
oh_my_thats_long>;
template <typename T>
using parentA2 = anotherclass_with_long_name<and_many_other,
template_arguments_that,
are_also_annoying,
including_also,
T>;
}
名称空间详细信息
{
模板
使用parentA1=class_和_long_名称;
模板
使用parentA2=另一个具有长名称的类;
}
然后
template<typename T>
class A : detail::parentA1<T>, detail::parentA2<T>
{
};
template<typename T>
class A : detail::A::parent1<T>, detail::A::parent2<T>
{
};
模板
A类:详细信息::parentA1,详细信息::parentA2
{
};
我认为,最好的选择是你已经在做的事情。然而,如果你觉得你绝对不能容忍这一点,这里有一些有趣的代码(如果我在生产过程中的代码审查中看到类似的东西,我会竭尽全力摆脱它)
模板
struct inherit_public:public inherit_FROM。。。{
结构父类型{
模板结构获取{
使用type=typename get::type;
};
模板结构获取{
使用type=ARG;
};
};
模板使用parent=typename parent\u types::template get::type;
};
//**示例用法**
结构X{static constexpr const char*const name=“X”;};
结构Y{static constexpr const char*const name=“Y”;};
结构Z{static constexpr const char*const name=“Z”};
#包括
结构A:公开继承\u{
作废打印_父项(){
std::cout基于@Jarod的解决方案:如何在细节子空间中添加一个
namespace detail { namespace A {
template <typename T>
using parent1 = class_with_long_name<T,
and_many_other,
template_arguments,
oh_my_thats_long>;
template <typename T>
using parent2 = anotherclass_with_long_name<and_many_other,
template_arguments_that,
are_also_annoying,
including_also,
T>;
} // namespace A
} // namespace detail
名称空间详细信息{名称空间A{
模板
使用parent1=class_和_long_名称;
模板
使用parent2=另一个具有长名称的类;
}//名称空间A
}//名称空间详细信息
然后
template<typename T>
class A : detail::parentA1<T>, detail::parentA2<T>
{
};
template<typename T>
class A : detail::A::parent1<T>, detail::A::parent2<T>
{
};
模板
类别A:detail::A::parent1,detail::A::parent2
{
};
如果对所有类使用相同的访问说明符进行继承,则可以使用如下内容:
template <typename...S>
struct Bases : public S... {
template <size_t I>
using super = typename std::tuple_element<I, std::tuple<S...>>::type;
};
模板
结构基础:公共S{
模板
使用super=typename std::tuple\u元素::type;
};
这将使您能够按照通过super
从基类继承的顺序访问所有基类
简短示例:
#include <iostream>
#include <tuple>
template <typename...S>
struct Bases : public S... {
template <size_t I>
using super = typename std::tuple_element<I, std::tuple<S...>>::type;
};
class Foo
{
public:
virtual void f()
{
std::cout << "Foo";
}
};
class Fii
{
public:
virtual void f()
{
std::cout << "Fii";
}
};
class Faa : private Bases<Foo, Fii>
{
public:
virtual void f()
{
std::cout << "Faa";
super<0>::f(); //Calls Foo::f()
super<1>::f(); //Calls Fii::f()
std::cout << std::endl;
}
};
int main()
{
Faa faa;
faa.f(); //Print "FaaFooFii"
return 0;
}
#包括
#包括
模板
结构基础:公共S{
模板
使用super=typename std::tuple\u元素::type;
};
福班
{
公众:
虚空f()
{
std::cout您可以使用A::class\u和\u long\u name
或A::anotherclass\u和\u long\u name
template<typename T>
class A
: class_with_long_name<T, and_many_other, template_arguments, oh_my_thats_long>
, anotherclass_with_long_name<and_many_other, template_arguments_that, are_also_annoying, including_also, T>
{
// If you still want the typedefs.
using parent1 = typename A::class_with_long_name;
using parent2 = typename A::anotherclass_with_long_name;
// If you don't.
void foo() { A::class_with_long_name::bar(); }
};
模板
甲级
:带有长名称的类
,另一个名为长的类
{
//如果你还想要typedefs。
使用parent1=typename A::带有长名称的class\u;
使用parent2=typename A::另一个名为长的类;
//如果你没有。
void foo(){A::class_with_long_name::bar()}
};
您可以在上课前使用…
部件放置definition@Garf365,这会将这些名称引入作用域,它们对除类之外的任何人都没有意义。不要过于夸张。这些名称只在类内部有意义,所以请将它们保留在类内部。没有人因为重复两个名称而死亡。您可以这样做由于一个名为注入类名称的功能,没有任何类型的帮助器类。请参阅我的答案。在我看来,不污染作用域的最佳方法这确实会严重扩展(如果您有a、B、C、D、E、F和G,您很快就会用完个位数的父级:)只是为了好玩,我展示了我自己的解决方案,它没有细节混乱:)@einpoklum,不-这个例子是自包含的,正如提供的链接所示。我想知道我是否不应该像Simon Kraemer的那样喜欢std::tuple_元素。@einpoklum,如果你愿意,你可以使用tuple_元素。这几乎是一样的。我只是展示如何自己做到这一点——因为我相信展示的技术比实际实现的目标更有价值(如我所说,我不主张在real app中使用我或Simon的代码).我认为这是迄今为止最好的建议,尽管-这不是一个透明的改变,因为Faa
的子类现在必须意识到存在一个中间父类。此外,你是否也有这样的印象,这在生产代码中是不可接受的?@einpoklum我认为这取决于项目的规模。对于sm所有的程序都可以,但是谁需要在小程序中使用这种模板呢?我认为主要的问题是它很难阅读,因此容易出错(想想有人改变了基类的顺序,试着找出错误)。我认为您应该接受并使用@Jarod42的答案,因为它比我的解决方案更易于维护,但使用比parentA1
更有意义的名称。也许您也可以将其与simple的答案结合起来,但这也有问题。这是C++11?14?0x?我看到的主要问题是继承同一模板类时会发生什么两次使用不同的模板参数…@einpoklum此功能自C++98以来一直使用。