calling member function without object error: C++ / (G++) oop - c++

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;
}

Related

What's the correct way to let the static member function call a non-static member std::function in c++?

I'm using an open62541 library who's functions are almost all static. I have to write some callback functions in the open62541's functions, the callback functions are binding to some non-static function.
so the problem is how do I make the:
static function of class A call a std::function, which is bind to non-static function of class B ?
to make the question simpler I make the example:
#include <iostream>
#include <functional>
using namespace std;
namespace C {
std::function<void(void)>C_foo;
}
class B
{
public:
B()
{
C::C_foo=std::bind(&B::middleMan,this);
}
std::function<void(void)>B_foo;
void middleMan()
{
B_foo();
}
static void talkTheJoke()
{
C::C_foo();
}
};
class A
{
public:
void Knock_knock()
{
std::cout<<"who's there?"<<std::endl;
}
};
int main()
{
A m_A;
B m_B;
// response "who's there?"
m_A.Knock_knock();
m_B.B_foo=std::bind(&A::Knock_knock,m_A);
//response "who's there?" again "
B::talkTheJoke();
return 0;
}
There are class A and their non-static member function A:: Knock_knock(), I want class B's static member function can callback and also acts the same as A:: Knock_knock().
I put a B_foo there as a callback function which would bind the A:: Knock_knock(). Since the B::talkTheJoke() is static and B_foo is not, it seems that B::talkTheJoke() cannot call the B_foo.
So I put a namespace C as a middle man, the std:: function in C can be called by static function B::talkTheJoke(), it can also be bind to non-static std:: function B:: middleMan() which can call the B_foo.
The story would look like:
B::talkTheJoke() ----> m_B.B_foo --(std::bind)--> m_A.Knock_knock() ( X , not works )
B::talkTheJoke() ----> C::C_foo() --(std::bind)--> m_B.middleman() ----> m_B.B_foo --(std::bind)--> m_A.Knock_knock() ( O ,works )
However, this solution is really ugly,
what's the correct way to do so?
#include <iostream>
using namespace std;
class A
{
public:
void Knock_knock() {
std::cout<<"who's there?"<<std::endl;
}
};
class B
{
public:
static void setA( A *a ) {
m_A = a;
}
static void talkTheJoke() {
if ( m_A != nullptr )
m_A->Knock_knock();
}
private:
static A *m_A;
};
A* B::m_A = nullptr;
int main()
{
A m_A;
m_A.Knock_knock();
B::setA( &m_A );
B::talkTheJoke();
return 0;
}

How to pass an implemented virtual member function as a parameter

#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.

Polymorphic Member Variable

I got an elegant answer yesterday for my question regarding polymorphic object members.
But now I am facing the problem that the variable isn't really behaving the way I expected it to. The following code is being used:
#include <iostream>
#include <math.h>
using std::cin;
using std::cout;
using std::endl;
class Com
{
public:
virtual void setReady()
{
cout << "Com" << endl;
}
};
class DerivedCom : public Com
{
public:
void setReady()
{
cout << "DCom" << endl;
}
void somethingElse()
{
cout << "else" << endl;
}
};
class BaseClass
{
public:
Com* com;
public:
BaseClass(Com* c = new Com) : com(c)
{
}
virtual void setReady()
{
com->setReady();
}
};
class DerivedClass : public BaseClass
{
// the call to somethingElse() won't compile if I leave out this declaration
protected:
DerivedCom* com;
public:
DerivedClass() : BaseClass(new DerivedCom)
{
}
void setReady()
{
// This line causes a segfault if I put in the declaration earlier
this->com->setReady();
// This line won't compile if I leave out the declaration earlier
this->com->somethingElse();
}
};
int main()
{
DerivedClass* inst = new DerivedClass();
inst->setReady();
return 0;
}
The problem is, that DerivedClass::com is in fact of type DerivedCom but I can't access any DerivedCom-specific methods as the compiler won't find them. If I put in an extra re-declaration DerivedCom* com, the compiler will find the methods but I get segmentation faults.
Remove that extra declaration.
If you are sure that a Com* is a DerivedCom* then you can static_cast it.
static_cast<DerivedCom*>(this->com)->somethingElse();
This will likely crash it you're wrong however. So if you are not sure then you can dynamic_cast it
DerivedCom* dcom = dynamic_cast<DerivedCom*>(this->com);
if (dcom)
dcom->somethingElse();
dynamic_cast will return NULL if the object isn't of the type you asked for.
The reason for the segmentation faults is that you arent declaring the variable again with a different type, you are actually defining a new pointer in the derived class, one that is never initialized. Thus this->com->... will access the derived class com and crash since it is an uninitialized pointer.
What you are trying to do though, is to change the type of the member pointer. You could do that by making the type of the member pointer as a template variable, as follows
template <class ComType>
class BaseClassTemplate
{
ComType* com;
...;
};
typedef BaseClassTemplate<Com> BaseClass;
class DerivedClass : public BaseClassTemplate<DerivedCom>
{
...;
};
However this makes the base class a template, so to get it as you want it, you need to make an instantiation of BaseClass<Com> to get your version of base class. You can either make it a derived class or just a typedef as i have shown.

In C++ how can we call private function through an object without using friend function?

I came across this code written in C++ :
#include<iostream>
using namespace std;
class Base {
public:
virtual int fun(int i) { cout << "Base::fun(int i) called"; }
};
class Derived: public Base {
private:
int fun(int x) { cout << "Derived::fun(int x) called"; }
};
int main()
{
Base *ptr = new Derived;
ptr->fun(10);
return 0;
}
Output:
Derived::fun(int x) called
While in the following case :
#include<iostream>
using namespace std;
class Base {
public:
virtual int fun(int i) { }
};
class Derived: public Base {
private:
int fun(int x) { }
};
int main()
{
Derived d;
d.fun(1);
return 0;
}
Output :
Compiler Error.
Can anyone explain why is this happening ? In the first case , a private function is being called through an object.
Because in the first case you're using declaration from Base, which is public, and the call is being late-bound to the Derived implementation. Note that changing the access specifier in inheritance is dangerous and can nearly always be avoided.
Polymorphism is happening in the first case. It causes dynamic or late binding. And as mentioned in the second answer, it can become quite dangerous at times.
You cannot access the private interface of a class from the outside of class definition directly. If you want to access the private function in the second instance without using a friend function, as title of your question implies, make another public function in your class. Use that function to call this private function. Like this.
int call_fun (int i) ;
Call the fun() from inside it.
int call_fun (int i)
{
return fun (i) ; //something of this sort, not too good
}
The functions like this which are used just to call another function are known as wrapper functions.
Making friends is also not advisable always. It is against the principle of information hiding.

Passing objects into functions within another class c++

I'm learning about classes and objects in c++ and tried the following code to test if I understood it properly:
#include <iostream>
using namespace std;
class class1
{
public:
void write(int x)
{
dataObject.var = x;
}
};
class class2
{
public:
void read()
{
std::cout << dataObject.var;
}
};
class data
{
public:
int var;
data()
{
var = 1;
}
};
int main()
{
data dataObject;
class1 object1;
class2 object2;
object2.read(data dataObject);
object1.write(2);
object2.read(data dataObject);
return 0;
}
This was for two objects to both be used to modify and use the members of a third but I get the following errors:
In member function 'void class1::write(int)':
line 10: error: 'dataObject' was not declared in this scope
In member function 'void class2::read()':
line 14: error: 'dataObject' was not declared in this scope
In function 'int main()':
line 40 + 42: error: expected primary-expression before 'dataObject'
Any idea where I am going wrong?
Thanks in advance.
EDIT:
Thanks for all the suggestions. My code now is:
#include <iostream>
using namespace std;
class class1
{
public:
void write(data &dataObject, int x)
{
dataObject.var = x;
}
};
class class2
{
public:
void read(data dataObject)
{
std::cout << dataObject.var << endl;
}
};
class data
{
public:
int var;
data()
{
var = 1;
}
};
int main()
{
data dataObject;
class1 object1;
class2 object2;
object2.read(dataObject);
object1.write(dataObject,2);
object2.read(dataObject);
return 0;
}
And I now get the errors:
8 error: 'data' has not been declared
10 error: request for member 'var' in 'dataObject', which is of non-class type 'int'
18 error: 'data' has not been declared
20 error: request for member 'var' in 'dataObject', which is of non-class type 'int'
40 error: 'dataObject' was not declared in this scope
Where you go wrong is that at this point:
void write(int x)
{
dataObject.var = x;
}
there is no dataObject. You are trying to make your classes depend on some global object. First of all you have to decide if you really want this. And if you do, you need a way to ensure that these global objects are declared and instantiated before they get used by the classes.
There are many ways to fix the error, but first you need to be clear about what you want the classes to do and how they should interact with each other.
One example of how you could fix this without global objects:
class class1
{
public:
class1(data& dataObj) : dataRef_(dataObj) {}
void write(int x)
{
dataRef_.var = x;
}
private:
data& dataRef_;
};
Then in the main:
int main()
{
data dataObject;
class1 object1(dataObject);
object1.write(2);
}
Your classes are not aware of the variable dataObject. If you want them to be able to access instances of class data you will need to pass them to your functions. Redefine the functions like this
void read(const data& dataObject)
{
std::cout << dataObject.var;
}
or have a member variable of class data in your classes if you want to be able to do this.
From a design point of view, your classes don't do anything other than act on an instance of class data. You could combine both classes into new class that contains an object of class data as a member variable. You could have multiple functions (read/write) of that new class to do your modifications/output for the internal data member. It doesn't really make sense to have 2 separate classes whose only purpose is modifying another variable that is not a member variable.
You're passing parameters to member functions read and write, but those functions aren't defined as accepting parameters.
Redefine them as:
// for class1:
void write(data &dataObject, int x)
{
dataObject.var = x;
}
// for class2:
void read(data dataObject)
{
std::cout << dataObject.var << endl;
}
Furthermore, when you pass those objects, don't prefix them with the type data: you've already declared the variables, now you need only:
int main()
{
data dataObject;
class1 object1;
class2 object2;
object2.read(dataObject);
object1.write(dataObject, 2);
object2.read(dataObject);
}