Is there any keyword to override "all" methods of a template base class in a template derived class?

I know this seems like a silly question, but using object oriented material with C ++ templates is really troublesome. For example, Foo is a base class:

template <typename T> class Foo { public: virtual void Method1() { } virtual void Method1(int a) { } virtual void Method2() { } virtual void Method2(int a) { } //... lots of other methods }; 

Is there something like:

 template <typename T> class Bar : public Foo<T> { public: using Foo<T>::*; //redefine all inherited methods from Foo virtual void Method1(int a) { } virtual void Method2(int a) { } //other methods overloading.. }; 

Instead:

 template <typename T> class Bar : public Foo<T> { public: using Foo<T>::Method1 using Foo<T>::Method2 //... lots of other methods virtual void Method1(int a) { } virtual void Method2(int a) { } //other methods overloading.. }; 

So we can do:

 int main() { Bar<int> b; b.Method1(); b.Method2(); //... lots of other methods //This obviously works without the 'using' keyword: Foo<int>* f = &b; f->Method1(); f->Method2(); //etc return 0; } 
+4
source share
3 answers

No, there are no such functions, but this is usually not required. What you intend to do with using is already provided for by the basic inheritance mechanism.

You need to use using if overloads in the cast class hide methods from the base class or if you want to change the access mode, but not in general:

 class A { void f() {} public: void g(int) {} void h(int) {} }; struct B : A { using A::f; // make f public void g(double) {} using A::g; // otherwise A::g is hidden by the overload // using A::h isn't needed }; 

Note that you can still call A::h() through an instance of B , because nothing hides it.

+3
source

Not. Specialization of templates are separate types that are not inherited or do not belong to the general template. It is up to you to make sure they have the same implicit interface, and C ++ does not make this particularly easy.

See also this recent question, which may very well be what you are looking for. subclass as specialization - that is: adding a method to specialization

0
source

1. What is hiding

I'm afraid that something is wrong with your little example, and I suspect that your problems lie in Hiding .

Hiding is the first:

 struct Base { void foo(int) { std::cout << "Base" << std::endl; } }; struct Derived: Base { void foo(float) { std::cout << "Derived" << std::endl; } }; int main(int, char* argv[]) { Derived d; int integer = 1; float floating = 2; d.foo(floating); // outputs "Derived" as expected d.foo(integer); // outputs "Derived" too UhOh ? } 

The problem is called Hiding , it is a problem with name resolution at compile time. The problem is that before applying the overload rules to select the β€œright” method, the compiler must first compile the set of methods to consider. To do this, he will look at the most specialized area, and then spread out of one area at a time, until he finds the name he is looking for. Unfortunately (for efficiency reasons, I think), it stops as soon as it finds functions with a name.

So what happens here:

  • Look for methods named foo in Derived : { void Derived::foo(float) }

And stop ... therefore, trying to allow foo for the int argument, he chooses the only method he has seen so far, which may be a bit surprising.

You are right that you can surpass this with the using keyword, which brings names from a different scope so that the compiler can look at them. If I add using Base::foo; in the Derived definition, the compiler will do:

  • Look for methods named foo in Derived : { void Derived::foo(float) } + using
  • Add methods named foo to Base : { void Derived::foo(float), void Base::foo(int) }

And so you get what you want.

2. How to override a method

Now that you know what Hiding is and how to get around it, I would like to take the opportunity to consider your example flaws.

You should not override such methods:

 struct Base { void foo(int) const { std::cout << "Base" << std::endl; } }; struct Derived: Base { void foo(int) const { std::cout << "Derived" << std::endl; } }; 

The problem here is that she is just Hiding , and this can be surprising.

 void fooize(const Base& b) { b.foo(); } int main(int argc, char* argv[]) { Derived d; d.foo(); // output "Derived" fooize(d); // output "Base" } 

If you want to override, you will need the virtual . And then you will correct your classes as follows:

 struct Base { virtual ~Base() {} // Polymorphism means virtual destructor virtual foo(int) const { std::cout << "Base" << std::endl; } }; struct Derived: Base { virtual ~Derived() {} // Not necessary, but sweet reminder virtual foo(int) const; // virtual not necessary, but a sweet reminder again :) }; 

And then it will work as expected.

3. Cooks book on polymorphism

  • You must not override a method that is not virtual
  • So polymorphism means virtual Destructor (because it will be redefined anyway)
  • Inheritance introduces polymorphism, use composition if you do not want it.

Unfortunately, for C ++ there is no concept of "delegation", but we must deal with the cards that are given to us.

Final note: if a class has many methods ... perhaps it can benefit from a redesign (see std::string for an example of what not to do).

0
source

Source: https://habr.com/ru/post/1301764/


All Articles