• Welcome to Valhalla Legends Archive.
 

[C++] About virtual member functions

Started by NeBuR, January 16, 2004, 09:23 AM

Previous topic - Next topic

NeBuR

Hello. I have a couple of questions about class member functions declared as "virtual".

First, is there any sense in declaring (pure or not pure) virtual member functions under the private access modifier? I think that if a derived class must overload a virtual member funtion, it should see that function in his base class. But I'm not sure.

Second, is correct to change the access level of a virtual member function when redefining it in a derived class? If the answer is yes, then two main cases can appear:

   a) A virtual member function declared as public in the base class is redefined as protected/private in the derived one. In this way, you can break the protection level of the derived class member function by calling the base class' public version.

   b) A virtual member function declared as protected/private in the base class is redefined as public in the derived one. As you can't call the base class virtual member function, perhaps there is no sense in let it in the derived class.

Well, this is a strange question, which is giving me troubles. Thank you for your attention.

taylorjonl

Answer to the first question is that it isn't going to have any use since the derived classes don't have access to base classes private members.  If you try the compiler will complain that it can't access private members of base class.

Second answer is that you shouldn't do that and I don't really think it will work.  For one the purpose of a virtual function is for polymorpheism.  You do this so you can specialize the behavior of derived classes.  If you change the access level on the derived classes you are changing the interface.  So you define a public member in the base class and change the rights on the derived to protected the derived class is no longer compatibly with the base class's interface.

public base
{
public:
   virtual void Run() { printf("Base class Run() called\n");
}

public derived : public base
{
protected:
   void Run() { printf("Derived class Run() called\n");
}


Those classes cannot be interchangeable anymore.  This code below would fail.


int main(int argc, char** argv)
{
   base* pBase;

   pBase = new base();
   pBase->Run();
   pBase = new derived();
   pBase->Run();

   return 0;
}


We cannot access the Run() method in the derived class defeating the purpose of a virtual function.

NeBuR

Well, about the first question, I will say that is true that derived class can't see any base class private member. But derived class don't need to see it in order to redefining it. In fact, derived class don't need to call the base class virtual member function inside its own redefined one.

This example will prove that virtual member functions can be declared with private access:


class CBaseClass
{
public:
   void ShowNumber () { cout << GetNumber() << endl; }
private:
   virtual int GetNumber () { return(0); }
};


class CDerivedClass : public CBaseClass
{
private:
   int GetNumber () { return(1); }
};

void main ()
{
   CBaseClass   baseClassObject;
   CDerivedClass   derivedClassObject;

   baseClassObject.ShowNumber();
   derivedClassObject.ShowNumber();
}


The output of this code is this:

0
1

So my question is not if it's possible to declare private virtual member functions, but if it's a correct practice from the formal point of view of the object-oriented programming. I think that a derived class only can "know" those things that his base class (or classes) would show to it.

This seems a metaphisical question ;D

taylorjonl

I didn't realize that would work.

I would say that if it fits into your solution clearly then use it if not then don't.  I am not aware of any reason that it wouldn't be proper if it fit the situation.

NeBuR

I disagree with your second question example. The purpose of a virtual function is not polymorpheism, because function prototypes remain unchanged. Polymorpheism maintains the function name, but requires to change the parameter list, while virtual functions do not change neither name nor parameter list, only function body, along the inheritance graph (not always tree).

I've proved the next example, which is identical to yours:


class CBaseClass
{
public:
   virtual void ShowName () { cout << "I'm a CBaseClass object." << endl; }
};

class CDerivedClass : public CBaseClass
{
private:
   void ShowName () { cout << "I'm a CDerivedClass object." << endl; }
};

void main ()
{
   CBaseClass * baseClassObject   = new CBaseClass;
   CBaseClass * derivedClassObject   = new CDerivedClass;

   baseClassObject->ShowName();
   derivedClassObject->ShowName();
}


It runs fine, and produces the next output:

I'm a CBaseClass object.
I'm a CDerivedClass object.

Despite of this, I'm still thinking about the correctness of changing access level for virtual functions, from the design point of view.

PD: I suppose you've noticed that my English is far from perfection. Sorry. I'll try to write it the better I know, but improving it is a slow process.

Arta

Quote
The purpose of a virtual function is not polymorpheism, because function prototypes remain unchanged. Polymorpheism maintains the function name, but requires to change the parameter list [...]

This is not correct. Polymorphism doesn't require a change to the parameter list; quite the opposite is true. You might argue that this is pure virtual as opposed to virtual, but I'd argue that both are applications of the same principle:


class CBaseClass
{
public:
  virtual void ShowName ()  = 0; // Declare function as pure virtual
};

class CDerivedClass1 : public CBaseClass
{
private:
  void ShowName () { cout << "I'm a CDerivedClass1 object." << endl; }
};

class CDerivedClass2 : public CBaseClass
{
private:
  void ShowName () { cout << "I'm a CDerivedClass2 object." << endl; }
};

void main ()
{
  // CBaseClass cannot be instantiated directly.
  // Often we give the constructer protected access to enforce this
  CBaseClass *derivedClass1Object   = new CDerivedClass1;
  CBaseClass *derivedClass2Object   = new CDerivedClass2;

  derivedClass1Object->ShowName();
  derivedClass2Object->ShowName();
 
  /* Displays:
     I'm a CDerivedClass1 object
     I'm a CDerivedClass2 object.
  */   
}

NeBuR

There is a slight difference between Polymorphism anf Function Overloading.

As the term itself says, Polymorphism lets an entity (in this case, a function name) to have multiple forms (in this case, prototypes). Polymorphism can be used with class member functions (¿called methods? I'm not sure... please, correct me) and with no member ones, that is, those at global or namespace scope. Multiple forms with the same function name are really different functions, and so they can exist together at certain scope. In all cases, polymorphism requires not to have two functions with the same name and parameter list in the same scope (as you know, varying the function return type it's not enough to identify a new function).

On the other side, Function Overloading provides a new implementation or definition (a new function body) to a class member function, without modify neither its parameter list nor its return type. As overloaded functions are the same, two of them can not exist simultaneously at the same scope, and so each new version belongs to a different class in one inheritance line.

Pure or not pure, virtual class member functions are always overloaded functions, not polymorphed ones.

Arta[vL]'s last example are quite similar to the last I gave, but considering now pure virtual member functions. But what if we have the opposite case? It's correct for a class to overload a member function (virtual or not) declared as private inside its base class? The formal requirement for a class of viewing whatever it overload is what I'd like to discuss here, while the possibility of do the opposite (overload a function it doesn't view) has just been proved.

iago

Quote from: NeBuR on January 20, 2004, 06:56 AM
There is a slight difference between Polymorphism anf Function Overloading.

As the term itself says, Polymorphism lets an entity (in this case, a function name) to have multiple forms (in this case, prototypes)

Again, the opposite is true. Polymorphism means that an entity has a SINGLE form (ie, prototype) with MULTIPLE bodies (ie, its subclasses).
This'll make an interesting test for broken AV:
QuoteX5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*


NeBuR

 :-[ Sorry, because you've the truth, and I was wrong. I've interchanged both terms Polymorphism and Function Overloading. Sorry, again.

Fortunately, the concepts are still the same, and my question is still in air.

iago

I'm afraid I can't answer your question, because I don't know.

But don't get polymorphism and overloading mixed up, they are very, very different (in fact, opposite) concepts.
This'll make an interesting test for broken AV:
QuoteX5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*


StormGage

Quote from: NeBuR on January 16, 2004, 09:23 AM
First, is there any sense in declaring (pure or not pure) virtual member functions under the private access modifier? I think that if a derived class must overload a virtual member funtion, it should see that function in his base class. But I'm not sure.

The reason you may want to declare a function as private is that if your going to perhaps declare a function pointer as public to access that function in the private access of the class.  Typically, you would never do this with virtual functions because virtual functions must use pointers for their quote on quote "magic" to occur;  This interestingly enough can get overwhelmingly complicated, but if you can do it, by all means do it IMO.  In my experience though, I have never found I've needed to use private virtual functions, or private functions often unless for some reason I wanted to hide functions from derived classes that I didn't want to overide.  Pure virtual functions are used to create ADT's.  This singals to the clients of your class to a.) not to create an object to this class, derive from it; and b.) to overide all the functions of this class which derive from it.  ADT's (abstract datatypes created when using pure virtual functions) are for the interface of the classes which derive off of it, and are rarely used for implementation since you'll never create an object for them.

Quote from: NeBuR on January 16, 2004, 09:23 AM
   a) A virtual member function declared as public in the base class is redefined as protected/private in the derived one. In this way, you can break the protection level of the derived class member function by calling the base class' public version.

   b) A virtual member function declared as protected/private in the base class is redefined as public in the derived one. As you can't call the base class virtual member function, perhaps there is no sense in let it in the derived class.

When you derive from a class, all its class members, protected and public are put into the derived class in the same place they were in the base class.

class base
{
   public:
       int x;
   protected:
       int y;
};
class derived : public base
{
// this class will now have public x and protected y
};


If your going to declare virtual methods as private, then it shouldn't really matter..  you'll just have to use a  member function pointer to access the private function.  This is relatively pointless though if you plan to derive off of that class and want to use that method.  It's even more pointless to do that with a pure virtual function since the point of a pure virtual function is to create an ADT which is use for the interface of derived classes which you must overide all those functions of the ADT.

If you want more on pure virtual functions and virtual functions in polymorphism, you can PM me on these forums.

Arta

#11
I'm not entirely sure what you're getting at (perhaps a practical example would help) but this is not allowed, no:


class CBase
{
private:
  virtual void Function() { printf("Base\n"); };
};

class CDerived: public CBase
{
private:
   void Function() { printf("Derived\n"); };

public:
   void Print() { CBase::Function(); CDerived::Function(); }
};

int main(void)
{
   CDerived Derived;
   Derived.Print();

   return 0;
}


It would fail with a "cannot access private member blah blah" error.

As I said, I'm not really sure what you're getting at. The general idea behind making functions virtual in this manner is to allow derived classes to override the default behaviour of that function as defined by the base class. If you make the base class function private, it is inaccessible by derived classes, implying that you don't want them to call it. If you don't want them to call it, what's the sense in allowing them to override it? I think the problem here is one of logic rather than syntax.

NeBuR

Of course, it's a logic question, not one related to syntax. I've clear the syntax of virtual functions.

The third post of this thread contains an example of private virtual member functions, which compiles and runs without problems. But I think those functions should be protected instead private, at least the base class' one, because derived class must know of its existence in order to provide a new definition for it.

The reasons which bring me to think this is are the concepts involved, as inheritance, access level or polymorphism. Another time, I say this seems to be a metaphysical question ;D

Arta

I see what you mean. I suppose that could make sense, depending on the purpose of the class.

The access modifier stuff doesn't really matter, since (AFAIK) member functions called are always looked for in the current scope, before being looked for in base classes and finally in the global namespace. The fact that ShowNumber is inherited doesn't change that. Hence, CDerived does not in fact need to be able to 'see' CBase's private functions in order to be able to override them.

StormGage

Quote from: Arta[vL] on January 21, 2004, 05:45 AM
I'm not entirely sure what you're getting at (perhaps a practical example would help) but this is not allowed, no:
Are you referring to my comment on the subject?