octave-maintainers
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Octave_value class hierachy


From: John W. Eaton
Subject: Octave_value class hierachy
Date: Thu, 22 Apr 2004 12:37:34 -0500

On 22-Apr-2004, Jens Ruecknagel <address@hidden> wrote:

| Why is count a attribute of octave_value? Why is ref  *octave_value?
| Shouldn't it be: count attribute of octave_base_value and 
| octave_value::ref* octave_base_value?
| Wouldn't it be better to make octave_value the proxy class and 
| octave_base_value the referenced class? It is used this way anyway?
| 
| I'm just curios? Does anybody know the reason, I did not think of?

I think I followed the structure of the Number class hierarchy in
Coplien's "Advanced C++; Programming Styles and Idioms" book from
1992.  I must admit that at the time, that code seemed quite complex
to me, so probably I copied a lot more than I really understood.

Looking at the code now, I think the rep object must be a pointer to
an octave_value object so that the virtual functions in the
octave_value class work properly.

If you see another way to do this that is better, then please submit a
complete working example that demonstrates your ideas.  It can be
greatly simplified compared to the octave_value classes (for example,
just two derived types and one or two operations on them).  You could
start with the code in the first attachment below, and fix it so that
it works correctly.  Currently, both calls to the functions in main
end up in the methods of base_value class when only the one for
type_two should.  When you are done, I think you will probably end up
with something much like what is in the second attachment, which is a
simplified version of the current octave_value hierarchy.  But maybe
there is a simpler and better way that I'm not seeing.  In any case,
going through the exercise yourself will probably help you to
understand why things are the way they are.

jwe

#include <iostream>

class base_value;

class value
{
public:

  value (int t = 0);

  value (const value& v);

  value& operator = (const value& v);

  virtual ~value (void);

  virtual value fun (void) const;

private:

  base_value *rep;
};

class base_value
{
  friend class value;

public:

  base_value (void) { count = 1; }

  value fun (void) const
  {
    std::cerr << "base_value::fun" << std::endl;
    return value ();
  }

private:

  int count;
};

class type_one : public base_value
{
public:

  type_one (void) : base_value () { }

  value fun (void) const
  {
    std::cerr << "type_one::fun" << std::endl;
    return value ();
  }
};

class type_two : public base_value
{
public:

  type_two (void) : base_value () { }

  // Let the base class handle this one...
  // value fun (void) const
};

value::value (int t)
{
  switch (t)
    {
    case 1:
      rep = new type_one ();
      break;

    case 2:
      rep = new type_two ();
      break;

    default:
      rep = new base_value ();
      break;
    }
}

value::value (const value& v)
{
  rep = v.rep;
  rep->count++;
}

value&
value::operator = (const value& v)
{
  if (this != &v)
    {
      if (--rep->count == 0)
        delete rep;

      rep = v.rep;
      rep->count++;
    }
  return *this;
}

value::~value (void)
{
  if (--rep->count == 0)
    delete rep;
}

value
value::fun (void) const
{
  return rep->fun ();
}

int
main (void)
{
  value one (1);
  value two (2);

  // Should call type_one::fun
  one.fun ();

  // Should call base_value::fun, because type_two does not
  // implement fun.
  two.fun ();

  return 0;
}
#include <iostream>

class base_value;

class
xvalue
{
public:

  xvalue (void) { }
};

class value
{
public:

  value (int t = 0);

  value (const value& v)
  {
    rep = v.rep;
    rep->count++;
  }

  value& operator = (const value& v)
  {
    if (this != &v)
      {
        if (--rep->count == 0)
          delete rep;

        rep = v.rep;
        rep->count++;
      }
    return *this;
  }

  virtual ~value (void)
  {
    if (rep && --rep->count == 0)
      {
        delete rep;
        rep = 0;
      }
  }

  virtual value fun (void) const { return rep->fun (); }

private:

  union
  {
    value *rep;
    int count;
  };

protected:

  value (const xvalue&) : rep (0) { }
};

class base_value : public value
{
public:

  base_value (void) : value (xvalue ()) { }

  base_value (const base_value&) : value (xvalue ()) { }

  ~base_value (void) { }

  value fun (void) const
  {
    std::cerr << "base_value::fun" << std::endl;
    return value ();
  }
};

class type_one : public base_value
{
public:

  type_one (void) : base_value () { }

  ~type_one (void) { }

  value fun (void) const
  {
    std::cerr << "type_one::fun" << std::endl;
    return value ();
  }
};

class type_two : public base_value
{
public:

  type_two (void) : base_value () { }

  ~type_two (void) { }

  // Let the base class handle this one...
  // value fun (void) const
};

value::value (int t)
{
  switch (t)
    {
      case 2:
        rep = new type_two ();
        rep->count = 1;
        break;

    default:
      rep = new type_one ();
      rep->count = 1;
      break;
    }
}

int
main (void)
{
  value one (1);
  value two (2);

  // Should call type_one::fun
  one.fun ();

  // Should call base_value::fun, because type_two does not
  // implement fun.
  two.fun ();

  return 0;
}

reply via email to

[Prev in Thread] Current Thread [Next in Thread]