why can't access member function of base class in thus siutation? - c++

I'm so confused, why I can't access void func(int i), anybody can help me?
Of course this is just a demo to help your understand my question easily. Its real code is huge, I want the member functions in Base and Child both available.
The output always is
**
double
2
**
struct base
{
void func(int i)
{
cout << "int" << endl;
cout << i << endl;
}
};
struct child : base
{
void func(double d)
{
cout << "double" << endl;
cout << d << endl;
}
};
child c;
c.func((int)2);

Because child::func hides base::func.
You need to either make it visible in the derived class by bringing the name in scope:
struct child : base
{
using base::func;
void func(double d)
{
cout << "double" << endl;
cout << d << endl;
}
};
or call the base version explicitly by qualifying the name at the call site:
c.base::func(2);

The implicit conversion from int to double is masking the actual problem. If you change your base class func parameter type from int to string:
struct base
{
void func(string i)
{
cout << "string" << endl;
cout << i << endl;
}
};
Then you'd receive the following error to make it clearer:
func.cpp: In function `int main()':
func.cpp:27: error: no matching function for call to `child::func(const char[13])'
func.cpp:17: note: candidates are: void child::func(double)
Where you can see it only has visibility of child::func not base::func

Related

Usage of virtual keyword VS simple redefining in C++

I know that virtual functions are declared in base class and can be (don't have to be unless it's a pure virtual function) refined in a derived class. However, I don't understand the difference between redefining a virtual function and redefining a regular function. Looking at this example code:
class base {
public:
virtual int getAge(){
return 20;
}
int getId(){
return 11111;
}
};
class dri : public base{
public:
int getAge(){
return 30;
}
int getId(){
return 222222;
}
};
int main(){
dri d;
std:: cout << d.getAge() << std::endl;
std:: cout << d.getId() << std::endl;
return 0;
}
will output:
30
222222
in which case having the virtual keyword there didn't make any difference. both functions were overwritten. So why is it needed?
You didn't give an example of your class member function invocation. I guess you write the following code:
dri sth;
cout << sth.getAge() << endl;
cout << sth.getId() << endl;
However, please note that c++'s dynamic binding and polymorphism can only be applied when the instance is a pointer or reference, which actually means you should do this to get your ideal output:
base *sth = new dri();
cout << sth->getAge() << endl;
cout << sth->getId() << endl;

How to call a C++ class method, which is given as a parameter?

I'm trying to pass a method as a parameter to other method.
Magner.h:
Class Manager{
public:
timeCount(void (Manger::*function)(void));
void passedFuction();
}
In Manager.cpp, I'm trying to call timeCount by
timeCount(&Manager::passedFuction());
TimeCount Body:
void Manager::timeCount(void(Manager::*function)(void))
{
std::cout << "It works";
(*function)(); // here is error
}
ViusalStudio says:
void*Manager::*function)() operand of '*' must be a pointer
How should i correct it?
The example i was learing by was : http://www.cplusplus.com/forum/beginner/6596/
A pointer-to-member-function (pmf) is not a pointer. Let me repeat that:
A pointer-to-member-function is not a pointer.
To call a pmf, you have to provide it with the object you want to call it on. You probably want:
(this->*function)();
If you had another object obj of the right type, you could also use:
(obj.*function)();
The void (Manger::*function)(void) syntax is for member functions of Manager class, which cannot be used with functions outside the Manager class.
To fix this shortcoming, pass std::function<void(void)> instead, which would let you invoke itself using the regular function invocation syntax:
void Manager::timeCount(std::function<void(void)> f) {
std::cout << "It works";
f();
}
Here is a complete demo of how to call timeCount with member and non-member functions:
struct Manager {
string name;
void timeCount(std::function<void(void)> f) {
std::cout << "This is " << name << " manager" << endl;
f();
}
};
void foo() {
cout << "I'm foo" << endl;
}
struct Test {
int x;
void bar() {
cout << "I'm bar " << x << endl;
}
};
int main() {
Manager mgr {"time"};
mgr.timeCount(foo);
Test tst = {234};
mgr.timeCount(std::bind( &Test::bar, tst));
return 0;
}
Demo.
Since c++17, we have std::invoke:
std::invoke(function, this);
or
std::invoke(function, *this);
are both ok. Minimal demo:
#include <functional>
#include <iostream>
class Manager
{
public:
void timeCount(void (Manager::*function)(void));
void passedFuction()
{
std::cout << "call passedFunction\n";
}
};
void Manager::timeCount(void (Manager::*function)(void))
{
std::cout << "It works\n";
std::invoke(function, *this);
// (*function)(); // here is error
}
int main()
{
Manager a;
a.timeCount(&Manager::passedFuction);
}
It works
call passedFunction
live demo

Weird template and member function pointer error (C2373, C2530)

I came up with the following code when learning signal & slot, template, and function pointer.
Basically I am trying to make 2 classes, the base one will takes normal function pointers while the derived one will takes member function and wrap it up with a normal function, then pass it to the base class for invoking.
Here is the code:
#include<iostream>
struct foo {
void onNotify(int a, int b) {
std::cout << "member function: this=" << this << " a=" << a << " b=" << b << "\n";
}
};
void onNotify(void*, int a, int b) {
std::cout << "normal function: no context needed! a=" << a << " b=" << b << "\n";
}
// invoker that will takes normal functions.
template <typename...>
class invoker{
public:
invoker(void (*fptr)(void*, int, int), void* context){
fptr(context, 1, 2);
}
private:
invoker(){}
};
// invoker that will takes member functions.
template<class T>
class invoker<T> : public invoker<>{
public:
invoker<T>(T* context) : invoker<>(&forwarder, context){}
private:
invoker<T>(){}
static void forwarder(void* context, int i0, int i1) {
static_cast<T*>(context)->onNotify(i0, i1);
}
};
int main()
{
invoker<>(&onNotify, 0); // OK.
invoker<foo>(new foo); // OK.
invoker<foo>(0); // OK.
foo foo_;
auto f = invoker<foo>(&foo_); // OK.
// Errors:
// C2373 : 'foo_' : redefinition; different type modifiers.
// C2530 : 'foo_' : reference must be initialized.
invoker<foo>(&foo_); // ERROR!
return 0;
}
My questions are:
1) What is causing the compile error?
2) Why invoker<foo>(0); will actually run without error?
Thanks in advance!
1) The problem is that
invoker<foo>(&foo_);
is parsed as a definition of variable foo_ that has type invoker<foo>& rather than a call to the ctor of invoker<foo>. There is a number of ways to fix this, for example, use extra parentheses:
(invoker<foo>)(&foo_);
2) The code
invoker<foo>(0);
compiles without an error because it's unambiguous (it can't be interpreted as a declaration).

Casting base class to derived through std iterator in C++

in my program I have base GeneralHeader, MacHeader that derived from GeneralHeader and NetworkPacket with member Headers that is std list of GeneralHeader:
//Packet.h
enum HeaderType_t {General_Header_type, MAC_Header_type};
class GeneralHeader {
public:
bool Valid;
HeaderType_t HeaderType;
void PrintMe();
};
struct MACHeader: public GeneralHeader {
long unsigned DestAddr:48;
long unsigned SourceAddr:48;
void PrintMe();
};
struct Packet_t {
list<GeneralHeader> Headers;//TODO GeneralHeader
list<GeneralHeader>::iterator it_Header; //TODO GeneralHeader
void PrintMe();
};
While implementing the PrintMe() of Packet_t, that supposed to print all Headers according to HeaderType: if there is a GeneralHeader - it will use GeneralHeader.PrintMe() and if it is MACHeader in the list - it will print MACHeader.PrintMe())
I'm struggling to cast it_Header iterator from base GeneralHeader to derived MACHeader inside Packet_t method PrintMe():
//Packet.cpp
void GeneralHeader::PrintMe() {
std::cout << "Valid " << GeneralHeader::Valid << endl;
std::cout << "Header Type " << GeneralHeader::HeaderType << endl;
};
void HW_MACHeader::PrintMe() {
std::cout << "------------------------ " << endl;
std::cout << "---- MAC HEADER --- " << endl;
std::cout << "------------------------ " << endl;
GeneralHeader::PrintMe();
};
void NetworkPacket_t::PrintMe() {
std::cout << "Valid Packet " << NetworkPacket_t::ValidPacket << endl;
for (it_Header = Headers.begin(); it_Header != Headers.end(); it_Header++) {
switch (it_Header->HeaderType) {
case MAC_Header_type:
static_cast<HW_MACHeader*>(it_Header)->PrintMe();
break;
default:
std::cout << "default" << endl;
};
it_Header++;
};
};
The error: invalid static_cast from type 'std::_List_iterator' to type 'MACHeader*'
Thank you for any help.
The desired/normal polymorphic way would be:
Redefine PrintMe() to a virtual function so that cast is not necessary:
class GeneralHeader {
public:
bool Valid;
HeaderType_t HeaderType;
virtual void PrintMe();
};
class MACHeader: public GeneralHeader {
long unsigned DestAddr:48;
long unsigned SourceAddr:48;
public:
void PrintMe();
};
Also use vector of pointers to GeneralHeader:
list<GeneralHeader*>::iterator it_Header;
Then you can:
(*it_Header)->printMe();
The for loop will be simpler:
for (it_Header = Headers.begin(); it_Header != Headers.end();++it_Header)
(*it_Header)->PrintMe();
I don't know why you need the it_Header to be a member of the class? Can't it just be local to the loop?
You need to dereference it_Header to access the "underlying" object to address the compiler error :
static_cast<HW_MACHeader*>(*it_Header)->PrintMe();
Hoever, that will not solve your problem: you have a list of GeneralHeader; therefore because you want to downcast to an instance of HW_MACHeader, you need to use dynamic_cast; this has to be done either on a reference or a pointer:
dynamic_cast<HW_MACHeader&>(*it_Header).PrintMe();
The line above takes the object "referenced" by it_Header, and tells the compiler to cast it dynamically to a reference of type HW_MACHeader.
Note that dynamic_cast will return a null pointer if it cannot cast down to the type you want.
However, this is not a proper way to do this. You should follow user2672165's advice, and use virtual functions.

c++ lambda expressions variables in classes

I want to save lambda expressions variables (like in the fist code block). The problem is that then I use a classes (like the second code block) the compiler return me some errors. I don"t know how to fix it.
I hope somebody can help me and explain, why it's not working like this. Thanks.
First Code:
// variable for function pointer
void (*func)(int);
// default output function
void my_default(int x) {
cout << "x =" << "\t" << x << endl << endl;
}
int main() {
cout << "Test Programm\n\n";
// 1. Test - default output function
cout << "my_default\n";
func = &my_default;
func(5);
// 2. Test - special output function 2
cout << "my_func2\n";
func = [](int x) { cout << "x =" << " " << x << endl << endl; };
func(5);
return 0;
}
Second Code:
class test {
private:
// variable for function pointer
void (*func)(int);
// default output function
void my_default(int x) {
cout << "x =" << "\t" << x << endl << endl;
}
public:
void dummy(void) {
// 1. Test - default output function
cout << "my_default\n";
func = &my_default;
func(5);
// 2. Test - special output function 2
cout << "my_func2\n";
func = [](int x)->int{ cout << "x =" << " " << x << endl << endl; };
func(5);
}
};
// entry
int main() {
cout << "Test Programm\n\n";
test a;
a.dummy();
return 0;
}
Compiler:
pi#raspberrypi ~/dev/property $ gcc -std=c++0x -o test2 test2.cpp -lstdc++
test2.cpp: In member function ‘void test::dummy()’:
test2.cpp:491:17: error: ISO C++ forbids taking the address of an unqualified or parenthesized non-static member function to form a pointer to member function. Say ‘&test::my_default’ [-fpermissive]
test2.cpp:491:17: error: cannot convert ‘void (test::*)(int)’ to ‘void (*)(int)’ in assignment
test2.cpp:496:77: error: invalid user-defined conversion from ‘test::dummy()::<lambda(int)>’ to ‘void (*)(int)’ [-fpermissive]
test2.cpp:496:28: note: candidate is: test::dummy()::<lambda(int)>::operator int (*)(int)() const <near match>
test2.cpp:496:28: note: no known conversion for implicit ‘this’ parameter from ‘int (*)(int)’ to ‘void (*)(int)’
The problem is that member functions are not normal functions, they can't be assigned to a function pointer because the type in which they are member is part of their type.
Also, a member function needs to have an object to be called on, which will be the this inside the function code.
You have several solutions:
allow only functions which are member of your class
void (*MyClass::func)(int); // but you can use it only with members of the class
use std::function
typedef std::function<void(int)> func;
The solution 2 is the simplest as std::function is designed to work with anything that is callable with the same signature as the one in the template parammetters.
Also, it's the only solution that allows you to store closures(objects from lambdas).
See C++11 styled callbacks? for details.
class test {
private:
// variable for function pointer
std::function< void ( int )> func;
// default output function
void my_default(int x) {
cout << "x =" << "\t" << x << endl << endl;
}
public:
void dummy(void) {
// 1. Test - default output function
cout << "my_default\n";
func = std::bind(&test::my_default, this, std::placeholders::_1);
// or
func = [&]( int i ){ my_default( i ); };
func(5);
// 2. Test - special output function 2
cout << "my_func2\n";
func = [](int x)->int{ cout << "x =" << " " << x << endl << endl; };
func(5);
}
};
// entry
int main() {
cout << "Test Programm\n\n";
test a;
a.dummy();
return 0;
}
A member function is not like an ordinary function, in that there has to be an instance of the class available in order to invoke it (i.e., the object that will become *this). You can't make an ordinary function pointer variable point to a member function.
If you want to create a function pointer that can be called using any instance of the class, you need a member function pointer. You would write
void (test::*func)(int);
to declare it,
func = &test::my_default;
to assign it, and
(this->*func)(5);
to call it. Of course, now you can't make a member function pointer point to a lambda.
If on the other hand you want to bind this as the instance and create an ordinary function from a member function, well, you can't actually make an ordinary function pointer to it. Instead you'll want an std::function object,
std::function<void(int)> func;
bind as follows:
func = std::bind(&test::my_default, this, std::placeholders::_1);
and then call normally. std::function works with lambdas just like a function pointer would.