development

C ++에서 "super"사용

big-blog 2020. 5. 13. 20:44
반응형

C ++에서 "super"사용


내 코딩 스타일에는 다음 관용구가 포함됩니다.

class Derived : public Base
{
   public :
      typedef Base super; // note that it could be hidden in
                          // protected/private section, instead

      // Etc.
} ;

이를 통해 생성자에서 "super"를 Base의 별칭으로 사용할 수 있습니다.

Derived(int i, int j)
   : super(i), J(j)
{
}

또는 재정의 된 버전 내의 기본 클래스에서 메서드를 호출 할 때도 :

void Derived::foo()
{
   super::foo() ;

   // ... And then, do something else
}

심지어 체인으로 묶을 수도 있습니다 (그러나 여전히 그 용도를 찾아야합니다).

class DerivedDerived : public Derived
{
   public :
      typedef Derived super; // note that it could be hidden in
                             // protected/private section, instead

      // Etc.
} ;

void DerivedDerived::bar()
{
   super::bar() ; // will call Derived::bar
   super::super::bar ; // will call Base::bar

   // ... And then, do something else
}

어쨌든, "typedef super"의 사용은 예를 들어 Base가 장황하고 /하거나 템플릿 일 때 매우 유용합니다.

사실 super는 C #뿐만 아니라 Java에서도 구현됩니다 (잘못된 경우가 아니라면 "base"라고합니다). 그러나 C ++에는이 키워드가 없습니다.

그래서 내 질문 :

  • 이 typedef 사용은 작업 코드에서 보지 못했습니까?
  • 이 typedef super Ok를 사용합니까 (즉, 사용하지 않을 강력한 이유가 있습니까)
  • "슈퍼"가 좋은 것이어야합니까, C ++에서 다소 표준화되어야합니까, 아니면 이미 typedef를 통한 사용입니까?

편집 : Roddy는 typedef가 비공개이어야한다는 사실을 언급했습니다. 이것은 파생 클래스가 클래스를 다시 선언하지 않으면 사용할 수 없다는 것을 의미합니다. 그러나 그것은 그것이 super :: super chaining을 막을 것이라고 생각합니다 (그러나 누가 울 겠는가?).

편집 2 : "슈퍼"를 대량으로 사용한 지 몇 달이 지나서 나는 Roddy의 견해에 전적으로 동의합니다. "슈퍼"는 사적이어야합니다. 나는 그의 대답을 두 번 찬성했지만 나는 할 수 없다고 생각합니다.


Bjarne Stroustrup 은 C ++의 Design and Evolution에서 C ++super처음 표준화 될 때 ISO C ++ 표준위원회에서 키워드로 간주 했다고 언급했습니다 .

Dag Bruck는 기본 클래스를 "상 속됨"이라고하며이 확장을 제안했습니다. 이 제안은 다중 상속 문제를 언급했으며 모호한 용도로 플래그가 지정되었습니다. Stroustrup조차도 확신했다.

토론 후 Dag Bruck (예, 제안을 한 사람)은 제안이 구현 가능하고 기술적으로 건전하며 주요 결함이 없으며 다중 상속을 처리했다고 썼습니다. 다른 한편으로, 벅에 대한 강타가 충분하지 않았으므로위원회는 더 어려운 문제를 처리해야합니다.

마이클 타이 만 (Michael Tiemann)이 늦게 도착한 후,이 게시물에서 요구 한 것과 같은 기술을 사용하여 조판 된 슈퍼가 잘 작동한다는 것을 보여주었습니다.

따라서, 이것은 아마도 표준화되지 않을 것입니다.

사본이 없으면 Design and Evolution 은 커버 가격으로 가치가 있습니다. 중고 사본은 약 $ 10에 구입할 수 있습니다.


나는 항상 슈퍼보다는 "상속 된"을 사용했습니다. (아마도 델파이 배경으로 인해), 클래스에서 '상속 된'이 잘못 생략되었지만 하위 클래스에서 사용하려고 할 때 문제를 피하기 위해 항상 개인용으로 만듭니다 .

class MyClass : public MyBase
{
private:  // Prevents erroneous use by other classes.
  typedef MyBase inherited;
...

새 클래스를 만들기위한 표준 '코드 템플릿'에는 typedef가 포함되어 있으므로 실수로 생략 할 기회가 거의 없습니다.

연쇄 "super :: super"제안은 좋은 생각이라고 생각하지 않습니다. 그렇게하는 경우 특정 계층 구조와 매우 밀접하게 연결되어 있으며 변경하면 문제가 발생할 수 있습니다.


이것에 대한 한 가지 문제는 파생 클래스에 대해 super를 재정의하는 것을 잊어 버린 경우 super :: something에 대한 호출은 정상적으로 컴파일되지만 원하는 함수를 호출하지 않을 것입니다.

예를 들면 다음과 같습니다.

class Base
{
public:  virtual void foo() { ... }
};

class Derived: public Base
{
public:
    typedef Base super;
    virtual void foo()
    {
        super::foo();   // call superclass implementation

        // do other stuff
        ...
    }
};

class DerivedAgain: public Derived
{
public:
    virtual void foo()
    {
        // Call superclass function
        super::foo();    // oops, calls Base::foo() rather than Derived::foo()

        ...
    }
};

Martin York이이 답변에 대한 의견에서 지적한 것처럼이 문제는 typedef를 public 또는 protected가 아닌 private로 만들어 제거 할 수 있습니다.


FWIW Microsoft는 컴파일러 __super 의 확장을 추가했습니다 .


Super (또는 상속 된)는 매우 좋은 것입니다. Base와 Derived 사이에 다른 상속 계층을 고정해야하는 경우 다음 두 가지만 변경하면됩니다. 1. "class Base : foo"및 2. typedef

내가 올바르게 기억한다면, C ++ 표준위원회는 Michael Tiemann이이 typedef 트릭이 효과가 있다고 지적 할 때까지 이것에 대한 키워드 추가를 고려하고있었습니다.

다중 상속에 관해서는 프로그래머 제어하에 있기 때문에 super1 및 super2 또는 무엇이든 원하는대로 할 수 있습니다.


방금 다른 해결 방법을 찾았습니다. 오늘 날 typedef 접근법에 큰 문제가 있습니다.

  • typedef에는 클래스 이름의 정확한 사본이 필요합니다. 누군가 클래스 이름을 변경했지만 typedef를 변경하지 않으면 문제가 발생합니다.

그래서 나는 매우 간단한 템플릿을 사용하여 더 나은 솔루션을 생각해 냈습니다.

template <class C>
struct MakeAlias : C
{ 
    typedef C BaseAlias;
};

그래서 지금 대신

class Derived : public Base
{
private:
    typedef Base Super;
};

당신은 가지고

class Derived : public MakeAlias<Base>
{
    // Can refer to Base as BaseAlias here
};

이 경우 BaseAlias비공개가 아니며 다른 개발자에게 경고 해야하는 유형 이름을 선택하여 부주의 한 사용을 방지하려고했습니다.


I don't recall seeing this before, but at first glance I like it. As Ferruccio notes, it doesn't work well in the face of MI, but MI is more the exception than the rule and there's nothing that says something needs to be usable everywhere to be useful.


I've seen this idiom employed in many codes and I'm pretty sure I've even seen it somewhere in Boost's libraries. However, as far as I remember the most common name is base (or Base) instead of super.

This idiom is especially useful if working with template classes. As an example, consider the following class (from a real project):

template <typename TText, typename TSpec>
class Finder<Index<TText, PizzaChili<TSpec> >, PizzaChiliFinder>
    : public Finder<Index<TText, PizzaChili<TSpec> >, Default>
{
    typedef Finder<Index<TText, PizzaChili<TSpec> >, Default> TBase;
    // …
}

Don't mind the funny names. The important point here is that the inheritance chain uses type arguments to achieve compile-time polymorphism. Unfortunately, the nesting level of these templates gets quite high. Therefore, abbreviations are crucial for readability and maintainability.


is this use of typedef super common/rare/never seen in the code you work with?

I have never seen this particular pattern in the C++ code I work with, but that doesn't mean it's not out there.

is this use of typedef super Ok (i.e. do you see strong or not so strong reasons to not use it)?

It doesn't allow for multiple inheritance (cleanly, anyway).

should "super" be a good thing, should it be somewhat standardized in C++, or is this use through a typedef enough already?

For the above cited reason (multiple inheritance), no. The reason why you see "super" in the other languages you listed is that they only support single inheritance, so there is no confusion as to what "super" is referring to. Granted, in those languages it IS useful but it doesn't really have a place in the C++ data model.

Oh, and FYI: C++/CLI supports this concept in the form of the "__super" keyword. Please note, though, that C++/CLI doesn't support multiple inheritance either.


I've quite often seen it used, sometimes as super_t, when the base is a complex template type (boost::iterator_adaptor does this, for example)


One additional reason to use a typedef for the superclass is when you are using complex templates in the object's inheritance.

For instance:

template <typename T, size_t C, typename U>
class A
{ ... };

template <typename T>
class B : public A<T,99,T>
{ ... };

In class B it would be ideal to have a typedef for A otherwise you would be stuck repeating it everywhere you wanted to reference A's members.

In these cases it can work with multiple inheritance too, but you wouldn't have a typedef named 'super', it would be called 'base_A_t' or something like that.

--jeffk++


After migrating from Turbo Pascal to C++ back in the day, I used to do this in order to have an equivalent for the Turbo Pascal "inherited" keyword, which works the same way. However, after programming in C++ for a few years I stopped doing it. I found I just didn't need it very much.


I don't know whether it's rare or not, but I've certainly done the same thing.

As has been pointed out, the difficulty with making this part of the language itself is when a class makes use of multiple inheritance.


I use this from time to time. Just when I find myself typing out the base class type a couple of times, I'll replace it with a typedef similar to yours.

I think it can be a good use. As you say, if your base class is a template it can save typing. Also, template classes may take arguments that act as policies for how the template should work. You're free to change the base type without having to fix up all your references to it as long as the interface of the base remains compatible.

I think the use through the typedef is enough already. I can't see how it would be built into the language anyway because multiple inheritence means there can be many base classes, so you can typedef it as you see fit for the class you logically feel is the most important base class.


I was trying to solve this exact same problem; I threw around a few ideas, such as using variadic templates and pack expansion to allow for an arbitrary number of parents, but I realized that would result in an implementation like 'super0' and 'super1'. I trashed it because that would be barely more useful than not having it to begin with.

My Solution involves a helper class PrimaryParent and is implemented as so:

template<typename BaseClass>
class PrimaryParent : virtual public BaseClass
{
protected:
    using super = BaseClass;
public:
    template<typename ...ArgTypes>
    PrimaryParent<BaseClass>(ArgTypes... args) : BaseClass(args...){}
}

Then which ever class you want to use would be declared as such:

class MyObject : public PrimaryParent<SomeBaseClass>
{
public:
    MyObject() : PrimaryParent<SomeBaseClass>(SomeParams) {}
}

To avoid the need to use virtual inheritance in PrimaryParenton BaseClass, a constructor taking a variable number of arguments is used to allow construction of BaseClass.

The reason behind the public inheritance of BaseClass into PrimaryParent is to let MyObject have full control over over the inheritance of BaseClass despite having a helper class between them.

This does mean that every class you want to have super must use the PrimaryParent helper class, and each child may only inherit from one class using PrimaryParent (hence the name).

Another restriction for this method, is MyObject can inherit only one class which inherits from PrimaryParent, and that one must be inherited using PrimaryParent. Here is what I mean:

class SomeOtherBase : public PrimaryParent<Ancestor>{}

class MixinClass {}

//Good
class BaseClass : public PrimaryParent<SomeOtherBase>, public MixinClass
{}


//Not Good (now 'super' is ambiguous)
class MyObject : public PrimaryParent<BaseClass>, public SomeOtherBase{}

//Also Not Good ('super' is again ambiguous)
class MyObject : public PrimaryParent<BaseClass>, public PrimaryParent<SomeOtherBase>{}

Before you discard this as an option because of the seeming number of restrictions and the fact there is a middle-man class between every inheritance, these things are not bad.

Multiple inheritance is a strong tool, but in most circumstances, there will be only one primary parent, and if there are other parents, they likely will be Mixin classes, or classes which don't inherit from PrimaryParent anyways. If multiple inheritance is still necessary (though many situations would benefit to use composition to define an object instead of inheritance), than just explicitly define super in that class and don't inherit from PrimaryParent.

The idea of having to define super in every class is not very appealing to me, using PrimaryParent allows for super, clearly an inheritence based alias, to stay in the class definition line instead of the class body where the data should go.

That might just be me though.

Of course every situation is different, but consider these things i have said when deciding which option to use.


I use the __super keyword. But it's Microsoft specific:

http://msdn.microsoft.com/en-us/library/94dw1w7x.aspx


This is a method I use which uses macros instead of a typedef. I know that this is not the C++ way of doing things but it can be convenient when chaining iterators together through inheritance when only the base class furthest down the hierarchy is acting upon an inherited offset.

For example:

// some header.h

#define CLASS some_iterator
#define SUPER_CLASS some_const_iterator
#define SUPER static_cast<SUPER_CLASS&>(*this)

template<typename T>
class CLASS : SUPER_CLASS {
   typedef CLASS<T> class_type;

   class_type& operator++();
};

template<typename T>
typename CLASS<T>::class_type CLASS<T>::operator++(
   int)
{
   class_type copy = *this;

   // Macro
   ++SUPER;

   // vs

   // Typedef
   // super::operator++();

   return copy;
}

#undef CLASS
#undef SUPER_CLASS
#undef SUPER

The generic setup I use makes it very easy to read and copy/paste between the inheritance tree which have duplicate code but must be overridden because the return type has to match the current class.

One could use a lower-case super to replicate the behavior seen in Java but my coding style is to use all upper-case letters for macros.

참고URL : https://stackoverflow.com/questions/180601/using-super-in-c

반응형