Pointer to member function vs. pointer to ordinary function

I'm slightly better than a novice at C, and I'm trying to pick up C++ by converting an existing program. I'm trying to define a class, "potentiometer," that will be used to read values from potentiometers hooked up to my device. Sometimes the potentiometers will be hooked directly to my device's input pins, and other times they will be hooked into an analog mux chip. In the first case, the potentiometer is read via a function called analogRead(). In the second, case an AnalogMux object is instantiated, and the call AnalogMux::AnalogRead() is used.

To handle this situation, I defined the potentiometer object's constructor to take a pointer to a function--the function that should be used to read the potentiometer's value. However, I think that I'm running into the issue where the difference between a pointer to a member function is not interchangeable with a pointer to an ordinary function. I've tried adding a second constructor definition, with a type that matches the definition of AnalogMux::AnalogRead() in the library's header file, but that also doesn't compile.

The problem, as I see it, is that for every "type" of function that may be passed into the constructor, I need not only a separate constructor, but also a separate variable in the private section of the class, to hold the pointer to the function. On top of that, I need to keep track of which constructor got called, so that I can use the proper read function. This all seems terribly cumbersome, and probably indicates that I'm going about it all wrong.

Any advice on how to handle this situation would be appreciated.

Here is my code:

#include "analogmuxdemux.h"

class potentiometer {
  byte pinNum;
  int (*readFunction)(byte);
  uint16_t (AnalogMux::*readFunction2);
public:
  potentiometer(byte, int (*)(byte));
  potentiometer(byte, uint16_t (AnalogMux::*)(uint8_t));
  int analogRead(); // analogreads the pot
};

potentiometer::potentiometer(byte p, int (*f)(byte)) {
  pinNum = p;
  readFunction = f;
}

potentiometer::potentiometer(byte p, uint16_t (AnalogMux::*f)(uint8_t)) {
  pinNum = p;
  readFunction2 = f;
}

int potentiometer::analogRead() {
  return readFunction(pinNum);
  // in reality, would need to determine which constructor got called, then call the appropriate function pointer.
}

AnalogMux aMux(1, 2, 3, A0); // instantiate a mux with control pins 1/2/3 and input on A0

potentiometer p1(A1, analogRead); // attached to pin A1
potentiometer p2(1, aMux.AnalogRead); // attached to input 1 on aMux

void setup() {
}

void loop() {
}
Last edited on
Use a polymorphic call wrapper to encapsulate the call (non-member function, member function etc).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#include <iostream>
#include <functional>

//#include "analogmuxdemux.h"
using byte = unsigned char ;
typedef unsigned char byte ; // or a typedef

struct AnalogMux
{
    int AnalogRead( byte pin )
    {
        std::cout << "AnalogMux::AnalogRead: pin == " << int(pin) << '\n' ;
        // read
        return 0 ;
    }
};

class potentiometer
{
    // http://en.cppreference.com/w/cpp/utility/functional/function
    using read_function_t = std::function< int(byte) >  ;
    //typedef std::function< int(byte) > read_function_t ; // alternate syntax

    byte pinNum;
    read_function_t readFunction ;

    public:
        potentiometer( byte, read_function_t fun );

        int analogRead(); // analogreads the pot
};

potentiometer::potentiometer( byte pin , read_function_t fun )
{
  pinNum = pin ;
  readFunction = fun ;
}

int potentiometer::analogRead()
{
  return readFunction(pinNum);
}

int non_member_AnalogRead( byte pin )
{
    std::cout << "non_member_AnalogRead: pin == " << int(pin) << '\n' ;
    // read
    return 0 ;
}

int main()
{
    AnalogMux aMux ; // instantiate a mux

    potentiometer p1( 1, non_member_AnalogRead ); // attached to pin 1
    p1.analogRead() ;

    // attached to input 4 on aMux
    // bind the function to AnalogMux::AnalogRead to be invoked on aMux
    // http://en.cppreference.com/w/cpp/utility/functional/bind
    potentiometer p2( 4, std::bind( &AnalogMux::AnalogRead, aMux, std::placeholders::_1 ) ) ;
    p2.analogRead() ;
}

http://ideone.com/PMtnhE
Thanks much. It's all meaningless to me right now, but I'll research it until I understand. Thanks a lot for the inline links as well.
Unless I'm missing something, from your description, it sounds like what you need is simply inheritance and polymorphism. See http://www.cplusplus.com/doc/tutorial/inheritance/ and http://www.cplusplus.com/doc/tutorial/polymorphism/

Your code can be structured something like (nothing has been compiled, so buyer beware):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Potentiometer
{
public:
    virtual int readAnalog() { /* do something and return an int */}
};

class MuxPotentiometer : public Potentiometer
{
public:
    MuxPotentiometer() : mux(1, 2, 3, A0) {}
    virtual int readAnalog() { return mux.readAnalog(); }

private:
    AnalogMux mux;
};


A reference or pointer to the base class will call the correct functionality because the function is declared virtual in the base class. The contrived example below shows how this can be done with references.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int getPotential(Potentiometer& meter)
{
    return meter.readAnalog();
}

int main()
{
    int pot;
    Potentiometer meter;
    int muxPot;
    MuxPotentiometer muxMeter;

    pot = getPotential(meter);
    muxPot = getPotential(muxMeter);
}


Since you already know which function pointers to pass when constructing your potentiometer object, simply change your logic to create the correct derived class object instead.


Note: The readAnalog() functions should probably not be inlined in real code. They are shown that way for brevity only.
Last edited on
@doug: I'm studying your example now. I was just coming back to say that a polymorphic function wrapper doesn't look like it will work for me, because my development environment (Arduino) doesn't support C++11, and it appears that polymorphic function wrappers are a C++11 feature.

EDIT: I've studied your code now and I think I see how it fits all together. The getPotential function works because a pointer to an object can also point to all objects derived from that object, right?

Your solution does require two separate classes, one for a pot on a mux and one for a pot by itself. And likewise, I would have to declare additional classes for any other special cases. Is this good practice for how to address this situation? My first intuition was to define a single potentiometer class, with a single read-function, so as to hide from the user the details of how exactly the read was occurring. So the user could simply say, "potentiometer p; p.analogRead();".
Last edited on
> because my development environment (Arduino) doesn't support C++11,
> and it appears that polymorphic function wrappers are a C++11 feature.

boost::function<> and boost::bind<>() can be used with old compilers. A web search reveals that the header-only boost libraries have been ported to Arduino. https://github.com/vancegroup/arduino-boost

The code in the earlier post, using boost::function<> and boost::bind<>():

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#include <iostream>
#include <boost/function.hpp>
#include <boost/bind.hpp>

//#include "analogmuxdemux.h"
typedef unsigned char byte ; // or a typedef

struct AnalogMux
{
    int AnalogRead( byte pin )
    {
        std::cout << "AnalogMux::AnalogRead: pin == " << int(pin) << '\n' ;
        // read
        return 0 ;
    }
};

class potentiometer
{
    // http://www.boost.org/doc/libs/1_54_0/doc/html/function.html
    typedef boost::function< int(byte) > read_function_t ; // alternate syntax

    byte pinNum;
    read_function_t readFunction ;

    public:
        potentiometer( byte, read_function_t fun );

        int analogRead(); // analogreads the pot
};

potentiometer::potentiometer( byte pin , read_function_t fun )
{
  pinNum = pin ;
  readFunction = fun ;
}

int potentiometer::analogRead()
{
  return readFunction(pinNum);
}

int non_member_AnalogRead( byte pin )
{
    std::cout << "non_member_AnalogRead: pin == " << int(pin) << '\n' ;
    // read
    return 0 ;
}

int main()
{
    AnalogMux aMux ; // instantiate a mux

    potentiometer p1( 1, non_member_AnalogRead ); // attached to pin 1
    p1.analogRead() ;

    // attached to input 4 on aMux
    // bind the function to AnalogMux::AnalogRead to be invoked on aMux
    // http://www.boost.org/doc/libs/1_54_0/libs/bind/bind.html
    potentiometer p2( 4, boost::bind( &AnalogMux::AnalogRead, aMux, _1 ) ) ;
    p2.analogRead() ;
}
@joshuahardwell,

The getPotential function works because a pointer to an object can also point to all objects derived from that object, right?


Right. And the virtual function allows derived-class-specific functionality to be performed from a base class pointer/reference pointing/referring to an object of the derived class.

Your solution does require two separate classes, one for a pot on a mux and one for a pot by itself. And likewise, I would have to declare additional classes for any other special cases. Is this good practice for how to address this situation?


I think it is. Inheritance makes sense when a specific class is a specialized version of a more general class. If you use the "is a" test on two classes, you can frequently find your inheritance hierarchies. Classic examples of this are:
Triangle "is a" Shape, so Triangle inherits from Shape.
Employee "is a" Person, so Employee inherits from Person.
Dog and Cat "are" Animals, so Dog and Cat inherit from Animal.

In your case, pot on a mux "is a" pot, so it makes sense for pot on a mux to derive from pot. Also, you only need to write the code that specializes the derived class. All derived class behavior that is common with the base class behavior is available automatically and does not have to be rewritten. In your example, I think the derived class will actually be very small unless you start finding a bunch of other differences between a pot and a pot on a mux.

My first intuition was to define a single potentiometer class, with a single read-function, so as to hide from the user the details of how exactly the read was occurring. So the user could simply say, "potentiometer p; p.analogRead();"


But that's not what you were doing in the code in your first post. You were going to do this:

1
2
potentiometer p1(A1, analogRead); // attached to pin A1
potentiometer p2(1, aMux.AnalogRead); // attached to input 1 on aMux 


You know ahead of time which potentiometer is on a mux, because you have to pass in the correct function. With a derived class, your equivalent code would be:

1
2
Potentiometer p1(A1); 
MuxPotentiometer p2(1);



Note: I originally skipped the byte argument to the constructor to reduce confusion when discussing inheritance. Here is another iteration of my example with that argument being handled:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Potentiometer
{
public:
    Potentiometer(byte p) : pinNum(p) {}
    virtual int readAnalog() { /* do something and return an int */}

private:
    byte pinNum;
};

class MuxPotentiometer : public Potentiometer
{
public:
    MuxPotentiometer(byte p) : Potentiometer(p), mux(1, 2, 3, A0) {}
    virtual int readAnalog() { return mux.readAnalog(); }

private:
    AnalogMux mux;
};
Topic archived. No new replies allowed.