#include <iostream>
class virtualClass{
public:
virtual int a() = 0;
};
class UnknownImplementation : public virtualClass{
public:
int a() override { return 1;}
};
class myFramework {
public:
int c(int (virtualClass::*implementedFunc)(void)){
implementedFunc();
return 2;
}
};
int main(){
//some user implements the virtual class and calls myFramework function
myFramework* mfp = new myFramework();
std::cout << mfp->c(&(UnknownImplementation::a)) << std::endl;
}
Hi, I am working on a framework that is supposed call an implemented virtual function and use it. It is similar to the code above.
The compiling errors I get are:
testVirtual.cpp: In member function ‘int myFramework::c(int (virtualClass::)())’: testVirtual.cpp:16:19: error: must use ‘.’ or
‘->’ to call pointer-to-member function in ‘implementedFunc (...)’,
e.g. ‘(... -> implementedFunc) (...)’ implementedFunc();
^ testVirtual.cpp: In function ‘int main()’: testVirtual.cpp:24:47: error: invalid use of non-static member
function ‘virtual int UnknownImplementation::a()’ std::cout <<
mfp->c(&(UnknownImplementation::a)) << std::endl;
How do I fix these problems?
Thanks in advance!
passing an instance of the implemented class and calling the function worked.
To build on sameerkn's comment, this code should be:
#include <iostream>
class virtualClass{
public:
virtual int a() = 0;
};
class mySubclass : public virtualClass{
public:
int a() override { return 1;}
};
int main(){
mySubclass * x= new mySubclass ();
// ...
std::cout << x->a () << std::endl;
}
The point here is that you can pass objects (or pointers) of type virtualClass around - even though they might actually be mySubclass objects in real life - and still wind up in the right implementation of a(). myFramework is entirely unnecessary.
That's what virtual methods are for - consumers of virtualClass don't need to know anything about classes that might - now or in the future - be derived from it, and if I have read your question correctly, this is what you want.
Related
Enemy.h
class Enemy
{
int hp;
public:
Enemy(int);
void setHP(int);
int getHP();
virtual int attack() = 0;
};
Enemy.cpp
Enemy::Enemy(int playerXP)
{
if (playerXP == 0) {
hp = rand() % 5 + 1;
}
else if (playerXP > 0) {
hp = rand() % (playerXP * 5) + 1;
}
}
void Enemy::setHP(int currentHP)
{
hp = currentHP;
}
int Enemy::getHP()
{
return hp;
}
Reaper.h
#pragma once
#include "Enemy.h"
class Reaper : public Enemy
{
public:
Reaper(int playerXP) : Enemy(playerXP)
{
}
int attack(int, int);
};
Reaper.cpp
int Reaper::attack(int pa, int php)
{
int eatk = 0;
if (pa == 0) {
eatk = php * .5;
}
else {
eatk = rand() % php * .25;
}
return eatk;
}
Error:
Object of abstract class type "Reaper" is not allowed:
Pure virtual function "Enemy:attack" has no overrider.
My question is.. Why am I getting this error? I'm trying to understand why I am getting this, and also any possible answers to solve it.
Reaper is abstract because it is not overriding the abstract Enemy::attack() method, it is overloading it instead. As such, you cannot create any object instances of Reaper directly.
When a derived class wants to override a virtual method of a base class, the derived method MUST have the same signature as the base method it is overriding. That means it has the same return type (or at least a compatible covariant return type), calling convention, parameter list, and constness.
Reaper::attack() has a different parameter list than Enemy::attack(). That is why Reaper::attack() is an overload instead of an override.
In C++11 and later, you can (and should) mark Reaper::attack() with the new override keyword, eg:
class Reaper : public Enemy
{
public:
...
int attack(int, int) override;
};
That way, the compiler will take extra steps to verify whether a compatible base method actually exists, and if none is found then it will issue more meaningful error messages. For example, this live demo produces these errors when using override as shown above:
prog.cpp:41:9: error: ‘int Reaper::attack(int, int)’ marked ‘override’, but does not override
int attack(int, int) override;
^~~~~~
prog.cpp: In function ‘int main()’:
prog.cpp:57:9: error: cannot declare variable ‘r’ to be of abstract type ‘Reaper’
Reaper r(0);
^
prog.cpp:34:7: note: because the following virtual functions are pure within ‘Reaper’:
class Reaper : public Enemy
^~~~~~
prog.cpp:11:17: note: virtual int Enemy::attack()
virtual int attack() = 0;
^~~~~~
The compiler doesn't realize that you want to override the attack function in the base class. It sees int attack() and int attack(int, int) as two different functions because they have different type signatures. The result is that your Reaper class has two functions, one of which is a pure virtual function. Using the override keyword can help to avoid these errors, although it is only available in C++11 and newer.
I've written code in cpp to test my understanding of dynamic dispatching. I think that in my program the output should be "I'm in NT". My reasoning is:
tMethod is defined to be virtual, so dynamic binding will be used
at run time the class-type of test is NT, so call to test->tMethod(ont) should look for the implementation inside NT
actual parameter ont is of type NT, so exact match is found to be NT's impementation of tMethod
However, the output of this program is "I'm in T".
What is wrong in my reasoning?
#include <iostream>
using namespace std;
class T {
public:
virtual void tMethod(T){
cout<<"I'm in T"<<endl;
}
};
class NT: public T{
public:
void tMethod(NT){
cout<<"I'm in NT"<<endl;
}
};
int main()
{
NT ont;
T* test=new NT();
test->tMethod(ont);
return 0;
}
This method:
void tMethod(NT){
does not override this one:
virtual void tMethod(T){
you have changed parameter type from NT to T
You can add override to turn this bug it into error:
void tMethod(NT) override {
will output:
main.cpp:16:18: error: 'void NT::tMethod(NT)' marked 'override', but does not override
void tMethod(NT) override {
[edit]
Your actual question is why C++ does not allow to overload functions across class inheritence, specifically to be able to access derived class functions using base class pointer. The reason is that language does not support this functionality. You can find similar question in Bjarne Stroustrup FAQ: Why doesn't overloading work for derived classes?
NT::tMethod() takes different parameter type to N::tMethod() so it doesn't override. Use the override keyword to protect against this:
#include <iostream>
using namespace std;
class T
{
public:
virtual void tMethod(T) {
cout << "I'm in T" << endl;
}
};
class NT: public T
{
public:
void tMethod(NT) override { // use override keyword here
cout << "I'm in NT" << endl;
}
};
int main()
{
NT ont;
T* test = new NT();
test->tMethod(ont);
return 0;
}
Now you should get a compile error because you marked MT::tMethod() as override but it doesn't because it takes a different parameter type.
You'd better use pointer or reference to base class as an argument in virtual method. If you need to work with a derived class in the overriden method then you can use dynamic_cast.
class T {
public:
virtual void tMethod(T*){
cout<<"I'm in T"<<endl;
}
};
class NT: public T{
public:
virtual void tMethod(T* t) override {
NT* nt=dynamic_cast<NT*>(t);
if (nt)
{
cout<<"I'm in NT as NT"<<endl;
}
}
};
int main()
{
NT ont;
T* test=new NT();
test->tMethod(&ont);
return 0;
}
I was wondering about an issue of execution order: if I have a class whose constructor calls a function f() of itself and then make a subclass which overrides that function and calls the superclass' constructor, which f() is executed?
To answer this question, I wrote this program:
#include <iostream>
using namespace std;
class Super
{
public:
Super();
void
f();
};
class Sub : public Super
{
public:
Sub();
void
f();
};
Super::Super()
{
this->f();
}
void
Super::f()
{
cout << "hello" << endl;
}
Sub::Sub()
: Super()
{
}
void
Sub::f()
{
cout << "world" << endl;
}
int
main()
{
Super super();
Sub sub();
sub.f();
return 0;
}
Originally, I did not include the sub.f() call in main(), but the program did nothing but exit with code 0, so I added it to test. Now, when I compile with
g++ -Wall -o super super.cpp
I get this error output:
super.cpp: In function ‘int main()’:
super.cpp:51:7: error: request for member ‘f’ in ‘sub’, which is of non-class type ‘Sub()’
sub.f();
^
Now I'm even more confused. Sub is clearly a class type. What have I missed?
When the super class constructor is running it only sees the part of the object that is the super class. So when the constructor of Super runs, it sees the object as an object of type Super so it will call Super::f.
As for your error, Sub sub(); declares a function sub which returns an object of type Sub. What you want is to create an object sub. To do this you can declare it like this Sub sub; or, if you are using C++11, like this: Sub sub{};. The same applies for Super super();.
I'm trying to refactor some visitor-pattern code to remove some code duplication. The crux of this task requires splitting function overloads from an existing API into two: some go into a base class whilst others go into a derived class which extends that base.
Upon trying to split the API between the base and derived classes I hit an unexpected compilation error. Attempting to put aside the visitor-related background to this, I've untangled/distilled my problem into the example (c++11) code that follows:
#include <iostream>
class X
{
public:
virtual const char * name() const =0;
};
class Y : public X
{
public:
virtual const char * name() const override { return "Y"; }
};
class Z : public X
{
public:
virtual const char * name() const override { return "Z"; }
};
class APIBase // The API is split between this base class...
{
public:
virtual void foo(Y & y) =0;
};
class APIDerived : public APIBase // ..and this derived class
{
public:
virtual void foo(Z & z) =0;
};
class APIImplementation : public APIDerived
{
public:
virtual void foo(Y & y) override {
std::cout << "foo(" << y.name() << ")" << std::endl;
}
virtual void foo(Z & z) override {
std::cout << "foo(" << z.name() << ")" << std::endl;
}
};
class A
{
public:
APIDerived & api() { return m_api; }
private:
APIImplementation m_api;
};
int main(int argc, char * argv[])
{
Y y;
Z z;
A a;
a.api().foo(y);
a.api().foo(z);
return 0;
}
The basic idea is that class A provides an implementation of the API defined in APIBase and APIDerived via the call api() which can then act on an object derived from class X and do something different depending on whether it's a Y or a Z.
I would expect this code to give me the following output when run:
foo(Y)
foo(Z)
However, upon compiling this code, gcc gives me the following error:
intf.cpp: In function ‘int main(int, char**)’:
intf.cpp:57:16: error: no matching function for call to ‘APIDerived::foo(Y&)’
a.api().foo(y);
^
intf.cpp:57:16: note: candidate is:
intf.cpp:30:16: note: virtual void APIDerived::foo(Z&)
virtual void foo(Z & z) =0;
^
intf.cpp:30:16: note: no known conversion for argument 1 from ‘Y’ to ‘Z&’
There are two ways I can make this example code compile and give the expected output, but I'm uncertain what differentiates them from the original in the compiler's (or C++ standard's) eyes.
1. Reunite the API by putting both foo() pure function declarations into either APIBase or APIDerived (but not split between them), e.g.:
class APIBase
{
public:
virtual void foo(Y & y) =0;
virtual void foo(Z & z) =0;
};
2. Change class A so that it derives from APIImplementation and ditch the api() redirection calls, e.g.:
class A : public APIImplementation {};
int main(int argc, char * argv[])
{
Y y;
Z z;
A a;
a.foo(y);
a.foo(z);
return 0;
}
I don't want to have to so either of these. Neither do I want to ditch inheritance in favour of templates.
I'm pretty new to C++: please can you help me understand why this example code fails to compile and, if possible, offer workarounds that won't require me to takes steps (1) or (2) above?
Technical details:
Platform: Centos 7, Linux 3.10.0-123.6.3.el7.x86_64
Compiler: gcc (GCC) 4.8.2 20140120 (Red Hat 4.8.2-16)
By default, an f in the base class and an f in a derived class are not treated as overloads and overload is not done between them.
The compiler basically walks backwards through scopes to find a scope where there's at least one item with the name it's looking for. Then it looks at everything with that name in that scope, and does overload resolution on them. If there's something at an outer scope from there (e.g., a parent class) with the same name, it will not be included in that overload resolution.
You can, however, bring the inherited name into scope:
struct base {
void foo(int);
};
class derived : public base {
using base::foo;
void foo();
};
Now, if you call foo in the derived class, the foos from the derived class and the base class are treated as an overload set, so the correct one to call will be based on the argument you pass (or lack thereof).
i was curious to know why the following throws an error in g++ (cannot call member function without object). I suppose a workaround would be to have the B class variable as static variable in A - but i was curious to find out why, when there is an instance of A's child class C created, this still throws an error - many thanks!
#include <iostream>
#include <cstring>
using namespace std;
class B {
public:
double var;
public:
friend class A;
B() : var(1) { };
void set(double new_rate);
};
class A {
protected:
B main_B;
public:
virtual void set_rate(double new_rate) { cout << "test";
//B.set(new_rate);
}
};
class C : public A {
};
/*
void B::set(double new_rate) {
var = new_rate;
cout << "worked " <<current_rate <<endl;
}
*/
int main() {
C test_C;
A::set_rate ( 2.00 );
return 0;
}
Firstly,
C test_c();
does not create an instance of C, it declares a function that returns a C. You mean:
C test_c;
Secondly, non-static member functions can only be called on a specific instance of a class. So with the corrected code, you could say:
test_c.set_rate( 2.0);
You can use an explicit <class>:: to call a non-static member function, thereby disabling any virtual function mechanism, but for a non-static member you still need to specify a class instance on which to call the function.
e.g.
int main()
{
C test_C;
test_C.A::set_rate(2.00);
return 0;
}