I want to define a function in a base class and a function with the same name and another signature in a subclass like this:
class A {
public:
void foo () {}
};
class B : public A {
public:
void foo(int x) {}
};
int main() {
B b;
b.foo();
}
But it causes compile error: no matching function for call to ‘B::foo()’.
If I comment foo definition in class B, it compiles.
How to solve the problem?
What I really want is to define a polymorhic interface in a base class and redefine semantic in child classes.
UPD: Thanks, the answers worked for this example. But it doesn't seem to work with templates:
sort.h
...
class Sort {
public:
template <typename TArr>
static TArr& sort(TArr& array) { return sort(array, array.size()); }
};
class BubbleSort : public Sort { // add inheritance
public:
using Sort::sort;
template <typename TArr>
static TArr& sort(TArr& array, size_t len) {
...
}
};
test.cpp
...
int main () {
...
std::array<int, 5> test_array {3, 2, 5, 1, 4};
BubbleSort::sort(test_array)
...
}
When I run this, I get:
sort.h: In instantiation of ‘static TArr& Sort::sort(TArr&) [with TArr = std::array<int, 5ul>]’:
test.cpp:9:30: required from here
sort.h:17:47: error: no matching function for call to ‘Sort::sort(std::array<int, 5ul>&, std::array<int, 5ul>::size_type)’
static TArr& sort(TArr& array) { return sort(array, array.size()); }
^
sort.h:17:16: note: candidate: template<class TArr> static TArr& Sort::sort(TArr&)
static TArr& sort(TArr& array) { return sort(array, array.size()); }
^
sort.h:17:16: note: template argument deduction/substitution failed:
sort.h:17:47: note: candidate expects 1 argument, 2 provided
static TArr& sort(TArr& array) { return sort(array, array.size()); }
Why does it happen?
UPD: Got that.
Without virtual, the A::foo() doesn't define a polymorphic interface.
Anyway, you can make A::foo() visible via B with a using declaration:
class B : public A {
public:
using A::foo;
void foo(int x) {}
};
This provides polymorphism to the extent that you accept function overloading as polymorphism--i.e., A::foo() and B::foo() form an overload set, and the compiler chooses which to call based on the parameter(s) you pass (if any), the same way as if B contained two overloaded functions (with the same signatures as the existing A::foo and B::foo).
But it causes compile error: no matching function for call to ‘B::foo()’
Try using-declaration:
class A {
public:
void foo() {}
};
class B : public A {
public:
using A::foo;
void foo(int x) {}
};
What I really want is to define a polymorphic interface in a base class and redefine semantic in child classes.
Well, you should make the base class function virtual an have the same parameters when override it. Otherwise, how the subclass function is supposed to be called via a reference/pointer to the base class?
Function f from the derived class simply hides all the functions with the same name from the base class.
To solve it you can use a using-declaration:
class B : public A {
public:
using A::foo;
void foo(int x) {}
};
Related
I've got a static factory method in a base class.
Because of some reasons I want to each derived class will be instantiated by this factory method hence all these classes have protected ctors.
In real situation the Create function does more additional logic along with error handling.
class Base
{
public:
virtual ~Base() {}
template <typename T>
static void Create(std::unique_ptr<T>& pOut)
{
pOut = std::unique_ptr<T>(new T);
// ...
}
protected:
Base() {}
};
class Derived : public Base
{
protected:
Derived() {}
};
int main()
{
std::unique_ptr<Derived> ptr;
Derived::Create(ptr);
}
That code obviously doesn't compile since we don't have access to the protected ctor.
prog.cc: In instantiation of 'static void Base::Create(std::unique_ptr<_Tp>&) [with T = Derived]':
prog.cc:33:24: required from here
prog.cc:17:35: error: 'Derived::Derived()' is protected within this context
17 | pOut = std::unique_ptr<T>(new T);
| ^~~~~
prog.cc:26:5: note: declared protected here
26 | Derived() {}
| ^~~~~~~
The first solution that seems to be the most common is friend declaration in derived class. However it works I don't like it because:
I have to add such declaration in each derived class
This is a friend
class Derived : public Base
{
protected:
Derived() {}
friend void Base::Create<Derived>(std::unique_ptr<Derived>&);
};
Thinking about more generic approach I was trying something like this:
template <typename T>
static void Create(std::unique_ptr<T>& pOut)
{
static_assert(std::is_base_of_v<Base, T>, "T should be Base-family class.");
class CreateHelper : public T
{
public:
static void InternalCreate(std::unique_ptr<T>& pOut)
{
pOut = std::unique_ptr<CreateHelper>(new CreateHelper);
// ...
}
};
CreateHelper::InternalCreate(pOut);
}
It works but looks weird to me and:
The real pointer type is CreateHelper however outside this function we don't see that
This approach needs that Base-familiy should be polimorphic since we use pointer to base class (it's seems this condition should be always met but still it's worth to mention about that)
My questions are
What do you think about the last approach?
Is it considered as a bad design?
In general, a far better approach here is to simply refer to simple construction helper classes, then you can refer to make_unique() too:
class Base
{
protected:
struct Accessor
{
explicit Accessor() = default;
};
public:
Base(Accessor) {}
virtual ~Base() {}
template <typename T>
static void Create(std::unique_ptr<T>& pOut)
{
pOut = std::make_unique<T>(Accessor());
// ...
}
};
class Derived : public Base
{
public:
Derived(Accessor) : Base(Accessor()) {}
};
Only drawback: Derived classes have to adapt their constructor(s) accordingly.
A general point: A factory should almost always be aware of its relevant types in general, at least of partial aspects of the relevant types, provided by polymorphism (interfaces) or/and via traits. So I think, this is a bit more convenient:
template <class T, typename std::enable_if<std::is_base_of<Base, T>::value>::type* = nullptr>
static void Create(std::unique_ptr<T>& pOut)
{
pOut = std::make_unique<T>(Accessor());
// ...
}
Further on: You might have to rethink about your general creation design here. The common approach here is to return the created object, not to fill a reference. With your current approach, you have to think about exception safety (contracts..) here at least twice for instance...
Possible approach:
template <class T, typename std::enable_if<std::is_base_of<Base, T>::value>::type* = nullptr>
static std::unique_ptr<T> Create()
{
auto pOut = std::make_unique<T>(Accessor());
// ...
return pOut;
}
Forgive the obscure title. It's likely a duplicate but I couldn't find the correct phrase.
Consider the following inheritance hierarchy.
class A
{
public:
virtual void Foo(int i) { printf("A::Foo(int i)\n"); }
void Foo(int a, int b) { Foo(a + b); }
};
class B : public A
{
public:
void Foo(int i) override { printf("B::Foo(int i)\n"); }
};
class C : public B
{
public:
void Bar() { Foo(1, 2); } //error C2660: function does not take two arguments
};
A has two methods named Foo with a different number of parameters. Only one of them is virtual.
B overrides the virtual method.
C tries to call the non-virtual method and encounters an error.
Calling the method as A::Foo(1, 2) does work fine.
Question:
Why can't the compiler deduce that the correct method is found on A?
It seems odd we would have to explicitly add A:: in a call such as:
C c;
c.A::Foo(1, 2);
Because the member function named Foo is found at the class scope of B, and then name lookup stops, so the Foo in class A is not visible, and won't be considered for overload resolution, even if the version in class A is more appropriate. It is name hiding.
You can use using to introduce them into the same scope, and make overload resolution work as you expect. Such as:
class C : public B
{
using A::Foo;
using B::Foo;
public:
void Bar() { Foo(1, 2); }
};
See Unqualified name lookup
LIVE
Here is a sample code:
#include <memory>
class A {
public:
template <class T> void f(std::unique_ptr<T>, int) {}
private:
virtual void f(int) = 0;
};
class B: public A {
public:
using A::f;
private:
virtual void f(int) override {}
};
int main() {
std::unique_ptr<float> a;
B* b = new B;
b->f(std::move(a), 1);
return 0;
}
When I compile it with clang++, I get an error:
'f' is a private member of 'A'
using A::f;
^
How to make the template method f(std::unique_ptr<T>, int) visible from class B?
Note: if the virtual method A::f(int) is moved to a public section - everything works fine.
By giving it distinct name from the completely unrelated private virtual f.
Having an overloaded function where different overloads have different access control level neither works nor makes sense. You should only use the same name if the functions actually do the same (or comparable given the arguments) thing, but than it does not make sense to make one public and one private.
If you have a public wrapper over private virtual (which is common, see e.g. std::basic_streambuf), just add suitable prefix/suffix to one of them (std::basic_streambuf uses pub on the public, but it usually makes more sense to add priv, impl or _ to the private virtual.
You can not use using for this as using can not distinguish between the template and the virtual f. What does work is a simple forwarder:
class B: public A {
public:
template <class T> void f(std::unique_ptr<T> p, int i)
{
A::f<T>(std::move(p),i);
}
private:
virtual void f(int) override {}
};
I have two classes as follows in a header file
template<size_t N>
class Parent{
protected:
char array[N];
size_t i;
public:
virtual void operator()(int i);
};
template<size_t N>
void Parent<N>::operator()(int i){
this->i = i;
}
class Child: public Parent<16>{
public:
virtual void operator()();
};
Child has operator()() defined elsewhere in a cpp file. Whenever I include this header file from another cpp file I can access operator()() but operator()(int) is not even defined. Why is this? I thought since I inherit from a specific instance of Parent, all the methods of it should be instanced as well and available.
Apart from the errors in your code, this is an example of hiding: Your derived class declares a function of the same name but with different signature as a base class. Thus the base function is hidden:
class A { virtual void foo(); };
class B : public A { virtual void foo(int); /* hides A::foo() ! */ };
Inheritance only affects functions that have the same signature (with some mild exceptions).
Your base class function is declared as void Parent<N>::operator()(int), while in your derived class you declare void Child::operator()().
In C++11 you can explicitly say virtual void foo(int) override to trigger a compiler error if the function isn't overriding anything.
If you intentionally want to define a new function with the same name as an existing one but with different signature, and not overriding the base function, then you can make the base function visible with a using directive:
class C : public A
{
using A::foo();
void foo(int);
}; // now have both C::foo(int) and C::foo()
Because the Parent's operator() hides the Child's operator() (they have different signatures). How come you are not getting warnings when you compile your code?
This is how it should be :
class Child: public Parent<16>{
public:
using Parent<16>::operator();
virtual void operator()();
};
If I have a code like this:
struct A {
virtual void f(int) {}
virtual void f(void*) {}
};
struct B : public A {
void f(int) {}
};
struct C : public B {
void f(void*) {}
};
int main() {
C c;
c.f(1);
return 0;
}
I get an error that says that I am trying to do an invalid conversion from int to void*. Why can't compiler figure out that he has to call B::f, since both functions are declared as virtual?
After reading jalf's answer I went and reduced it even further. This one does not work as well. Not very intuitive.
struct A {
virtual void f(int) {}
};
struct B : public A {
void f(void*) {}
};
int main() {
B b;
b.f(1);
return 0;
}
The short answer is "because that's how overload resolution works in C++".
The compiler searches for functions F inside the C class, and if it finds any, it stops the search, and tries to pick a candidate among those. It only looks inside base classes if no matching functions were found in the derived class.
However, you can explicitly introduce the base class functions into the derived class' namespace:
struct C : public B {
void f(void*) {}
using B::f; // Add B's f function to C's namespace, allowing it to participate in overload resolution
};
Or you could do this:
void main()
{
A *a = new C();
a->f(1); //This will call f(int) from B(Polymorphism)
}
Well I think first of all you did not understand what virtual mechanism or polymorhism. When the polymorphism is achieved only by using object pointers. I think you are new to c++. Without using object pointers then there is no meaning of polymorphism or virtual keyword use base class pointer and assign the desired derived class objects to it. Then call and try it.