From: baldwin@pacific.cps.msu.edu (Reid A Baldwin)
Subject: Re: Virtual Functions and Shared Memory
Organization: Dept. of Computer Science, Michigan State University
Date: Tue, 18 Aug 92 17:56:29 GMT

In article <1992Aug17.182423.14341@msuinfo.cl.msu.edu>, I write:
|> I am developing an application in which multiple processes communicate
|> via shared memory (UNIX). Unfortunately, virtual functions don't work for
|> objects in shared memory. The process that creates an object gets the
|> correct results, but other processes execute the function for the
|> base class instead of the derived class (using the pointer type instead
|> of the object type). I am not familiar with the implementation of virtual
|> functions. Is it possible to use virtual functions on objects that are
|> created by other processes and accessed via shared memory?
|> 
|> Thanks for your help,
|> Reid Baldwin
|> 
|> P.S. I will post a summary of responses if they are interesting.

Well, I solved it with a little help from
john%tollys.UUCP%bnrmtl.UUCP@Larry.McRCIM.McGill.EDU (John Hickin)
who responded:

>I am surprised that it works at all.  Normally i would expect a core dump but
>that may depend on the implementation.  cfront, for example, adds a pointer to
>each object using virtuals (actually there can be more than one such pointer
>if you are using multiple inheritance).  This pointer references a table of
>member function pointers.  Unfortunately, this virtual function table is in
>the memory space of the process which created the object.  Passing the object
>to another process through shared memory and running a virtual function can
>cause a segmentation violation.  If the processes involved are related via a
>fork (without an exec) and your brand of unix implements a copy-on-write policy
>for the parent's memory, then the child process can access the parent's virtual
>function tables without problem.

Here is what I wanted:

class first {
  char _name[10];
 :public
  first(char *name) {
    strncpy(_name, name, 10);
  }
  ~first();
  virtual void print() {
    printf("first %s\n", _name);
  };
};

class second : public first {
  char _name[10];
 :public
  second(char *name) : first(name) {};
  ~second();
  void print() {
    printf("second %s\n", _name);
  };
};

Here is what I had to do to get it:

first first_dummy("dummy");
second second_dummy("dummy");
class Vfirst {
 :public
  first *_list[2];
  Vfirst() {
    _list[0] = &first_dummy;
    _list[1] = &second_dummy;
  }
} dummies;

class first {
  char _name[10];
 :protected
  int _typind; /* indicates what type object is */
 :public
  first(char *name) {
    strncpy(_name, name, 10);
    _typind = 0;
  }
  ~first();
  void print() {
    dummies.list[_typind]->print(this);
  };
  virtual void print(first *it) {
    this = it;
    printf("first %s\n", _name);
  };
};

class second : public first {
 :public
  second(char *name) : first(name) {
    _typind = 1;
  };
  ~second();
  void print(first *it) {
    this = (second *) it;
    printf("second %s\n", _name);
  };
};


Basically, I never call the virtual function for an object in shared
memory. Instead, the print() function calls the print(first *) function
for an object in the processes own address space that has the same type
as the object in shared memory. This ensures that the correct function
is called. The object address must be passed explicitly instead of
relying on C++ to pass it implicitly. Unfortunately, I have to do some
extra stuff each time I make a new subclass or make a new virtual function.

Reid Baldwin
Newsgroups: comp.lang.c++