Member Function Pointer vs Virtual Function

I

Immortal Nephi

I did read Deitel – How to program c++ book. I did self-study at
home. I am very curious to see how polymorphism works. It does say –
switch logic can lead to error prone if programmers are not careful,
but virtual functions are easier to use.
Please state your opinion. Should you prefer to use member functions
array pointer or switch logic? Virtual function calls require triple
indirection pointer and it requires more execution time like CPU’s
overheads.
F_1(), F_2(), F_3(), and F_4() modify data members of class Test.
You only need to invoke Run(). Run() selects either F_1(), … F_4()
through member function array pointer.
I did read some websites on the google. It does mention – member
functions array pointer is very rarely used. It encourages you to use
virtual function instead.
If you put virtual on F_1(), … F_4(), vtable will be built in class
Test. It does not enable polymorphism unless you create four sub-
objects as four derived classes. Each derived class has Run(). They
should be able to invoke either F_1(), … F_4().
Please let me know. Do you recommend to use virtual function or
member function array pointer? Thanks…

class Test
{
public:

Test() : select_F(0), reg_data(0)
{
cout << "Test()" << endl;
F_PTR_ARRAY[0] = &Test::F_1;
F_PTR_ARRAY[1] = &Test::F_2;
F_PTR_ARRAY[2] = &Test::F_3;
F_PTR_ARRAY[3] = &Test::F_4;
}

~Test()
{
cout << "~Test()" << endl;
}

void Run()
{
(this->*F_PTR_ARRAY[select_F])();
}

void Run_Switch()
{
switch(select_F)
{
case 0:
F_1();
break;

case 1:
F_2();
break;

case 2:
F_3();
break;

case 3:
F_4();
break;
}

select_F++;
select_F &= 3;
}

void (Test::*F_PTR)();
void (Test::*F_PTR_ARRAY[4])();

void F_1()
{
cout << "F_1()" << endl;
reg_data = 10;
select_F++;
select_F &= 3;
}

void F_2()
{
cout << "F_2()" << endl;
reg_data = 40;
select_F++;
select_F &= 3;
}

void F_3()
{
cout << "F_3()" << endl;
reg_data = 100;
select_F++;
select_F &= 3;
}

void F_4()
{
cout << "F_4()" << endl;
reg_data = 150;
select_F++;
select_F &= 3;
}

int select_F;
int reg_data;
};

int main()
{
Test test;

test.Run();
test.Run();
test.Run();
test.Run();

// test.Run_Switch();
// test.Run_Switch();
// test.Run_Switch();
// test.Run_Switch();

system("pause");

return 0;
}
 
I

Immortal Nephi

If there is only one switch, then I prefer that, primarily because it is
more idiomatic. If there would end up being more than one switch
statement, then I would use polymorphism, primarily because it helps
keep code that changes together in the same place.


You are prematurely optimizing here. C++'s virtual dispatch system is
very fast. The execution overhead is very minor compared to ease of
understanding/modifying the code.

OK... Please give me your example source code. You can convert my
source code into polymorphism. I am not too sure how you can do it.
If base class is getting too large, you use derived class and inherit
data members and member functions. The problem is -- you must declare
and define derived classes in main() body. Assign base class pointer
to derived class. Then virtual function is working. However, I can
only declare and define one Test class in main() body.

You said if you have more than one switch statement. Polymorphism is
easier to read and understand source code. Please give me your
example how to use F_1(), ..., F_4(). Thanks...
 
A

Andrey Tarasevich

Immortal said:
Please let me know. Do you recommend to use virtual function or
member function array pointer?

I'd say you have to consider the pros and cons. What you are proposing
here is basically an attempt to create an individual copy of virtual
methods table (VMT) in each instance of the class (instead of a shared
VMT usually used in a traditional implementation of run-time
polymorphism). This gives you the following advantages/flexibilities
over the traditional implementation

Pros:

1. The ability to customize the polymorphic behavior of the class
instance at run-time by changing the corresponding pointer value in the
table. This can be done at the beginning of the instance's lifetime as
well as later, at any point of its lifetime.
2. The straighforward ability to base the selection of the method to
call on a run-time value (like an array index, for example), as opposed
to a compile-time identifier (method name) in traditional polymorphism.
3. Slightly faster call times.
4. Something else?

Cons:

1. Higher memory consumption (due to a separate VMT being stored in
each instance).
2. Higher maintenance costs. You have to declare the VMT manually,
and in general case you won't be able to use an array, since you'll need
different pointer types for different method signatures (unless you want
to fiddle with cast-based [semi-]hacks).
3. Loss of such features as covariant return types, since function
pointers do not support covariance (again, unless you want to fiddle
with casts).
4. Etc.

And the main question is do you really need this? I'd say that real-life
performance benefits of having an individual VMT in each instance are
virtually non-existent. So, unless you really need something as highly
customizable (at run-time) polymorphic behavior, there's really no point
in doing this.

Now, if you just need something as localized, simple and uniform as what
you have in your code sample, I'd go for the array-of-pointers approach
just because it is much cooler :)
 
I

Immortal Nephi

Immortal said:
   Please let me know.  Do you recommend to use virtual function or
member function array pointer?

I'd say you have to consider the pros and cons. What you are proposing
here is basically an attempt to create an individual copy of virtual
methods table (VMT) in each instance of the class (instead of a shared
VMT usually used in a traditional implementation of run-time
polymorphism). This gives you the following advantages/flexibilities
over the traditional implementation

Pros:

   1. The ability to customize the polymorphic behavior of the class
instance at run-time by changing the corresponding pointer value in the
table. This can be done at the beginning of the instance's lifetime as
well as later, at any point of its lifetime.
   2. The straighforward ability to base the selection of the method to
call on a run-time value (like an array index, for example), as opposed
to a compile-time identifier (method name) in traditional polymorphism.
   3. Slightly faster call times.
   4. Something else?

Cons:

   1. Higher memory consumption (due to a separate VMT being stored in
each instance).
   2. Higher maintenance costs. You have to declare the VMT manually,
and in general case you won't be able to use an array, since you'll need
different pointer types for different method signatures (unless you want
to fiddle with cast-based [semi-]hacks).
   3. Loss of such features as covariant return types, since function
pointers do not support covariance (again, unless you want to fiddle
with casts).
   4. Etc.

And the main question is do you really need this? I'd say that real-life
performance benefits of having an individual VMT in each instance are
virtually non-existent. So, unless you really need something as highly
customizable (at run-time) polymorphic behavior, there's really no point
in doing this.

Now, if you just need something as localized, simple and uniform as what
you have in your code sample, I'd go for the array-of-pointers approach
just because it is much cooler :)

Andrey,

Thanks for your advice. I agree with you because array of pointers
are much easier to invoke and select one of these member functions.
You always want to use simple base class when you always declare and
define one base class in main() body. What happen if base class is
getting larger? You might want to divide it into multiple source
codes. Derived classes through multiple diamond inheritance is the
answer. Always use virtual inheritance. Array of pointer is the
variable in base class. Then, you can choose any member functions
from one of these derived classes and reassign to array of pointer in
base class.

Do you agree?
 
I

Immortal Nephi

OK...  Please give me your example source code.  You can convert my
source code into polymorphism.  I am not too sure how you can do it.

Here is your example converted to the standard state pattern:

class Test;

class TestState {
public:
   virtual void run(Test* t) { }
   virtual int regData() const = 0;
protected:
   void changeState(Test* t, TestState* s);

};

class Test
{
friend class TestState;
   void changeState(TestState* s) {
      state = s;
   }

   int regData() const { return state->regData(); }
   TestState* state;
public:
   Test();
   ~Test();
   void Run();

};

void TestState::changeState(Test* t, TestState* s) {
   t->changeState(s);

}

class F1 : public TestState {
public:
   static TestState* instance();
   void run(Test* t);
   int regData() const;

};

class F4 : public TestState {
public:
   static TestState* instance() {
      static F4 state;
      return &state;
   }
   void run(Test* t) {
      cout << "F_4()\n";
      changeState(t, F1::instance());
   }
   int regData() const { return 150; }

};

class F3 : public TestState {
public:
   static TestState* instance() {
      static F3 state;
      return &state;
   }
   void run(Test* t) {
      cout << "F_3()\n";
      changeState(t, F4::instance());
   }
   int regData() const { return 100; }

};

class F2 : public TestState {
public:
   static TestState* instance() {
      static F2 state;
      return &state;
   }
   void run(Test* t) {
      cout << "F_2()\n";
      changeState(t, F3::instance());
   }
   int regData() const { return 40; }

};

TestState* F1::instance() {
   static F1 state;
   return &state;

}

void F1::run(Test* t) {
   cout << "F_1()\n";
   changeState(t, F2::instance());

}

int F1::regData() const { return 10; }

Test::Test(): state(F1::instance()) {
   cout << "Test()\n";

}

Test::~Test() {
   cout << "~Test()\n";

}

void Test::Run() { state->run(this); }

int main()
{
   Test test;

   test.Run();
   test.Run();
   test.Run();
   test.Run();

   system("pause");

   return 0;

}

Strictly speaking, the state pattern is not appropriate for your example
simply because all your example does is change data, behavior is
unchanged.

The best way to reproduce your output IMHO is something like this:

class Test
{
   struct State {
      string s;
      int i;
      State(const char* s, int i):s(s), i(i) { }
   };
   vector<State> states;
   int current;
public:
   Test() : current(0) {
      cout << "Test()\n";
      states.push_back(State("F_1()", 10));
      states.push_back(State("F_2()", 40));
      states.push_back(State("F_3()", 100));
      states.push_back(State("F_4()", 150));
   }
   ~Test() {
      cout << "~Test()\n";
   }
   void Run() {
      cout << states[current].s << '\n';
      ++current;
      current &= 3;
   }



};- Hide quoted text -

- Show quoted text -- Hide quoted text -

- Show quoted text -

Thanks for your example to the newsgroups. I have seen state pattern
on several websites. I thought--your example (vs rarely used member
function array pointer) should be shown to the public. I appreciate
your assistance. I do more C++ study. Thanks again. :)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top