Definition of Overriding in Owner Class

From Andrey

(Difference between revisions)
Revision as of 06:43, 3 February 2006
Andrey (Talk | contribs)

← Previous diff
Revision as of 07:13, 3 February 2006
Andrey (Talk | contribs)

Next diff →
Line 22: Line 22:
According to this definition, f() can be overridden ''in class B'' According to this definition, f() can be overridden ''in class B''
 +<pre>
class B { class B {
A a; A a;
int a::f(); int a::f();
}; };
 +</pre>
so that the following is true: so that the following is true:
-a.f(); // B::a::f() is called, not A::f()+ a.f(); // B::a::f() is called, not A::f()
-+
-A& r = a;+ A& r = a;
-r.f(); // B::a::f() is called, not A::f()+ r.f(); // B::a::f() is called, not A::f()
Now every time the client calls f() on B::a, B is aware of it. B also has the possibility to adapt f()'s implementation to its own needs. Now every time the client calls f() on B::a, B is aware of it. B also has the possibility to adapt f()'s implementation to its own needs.
-Example.+'''Example.'''
 +<pre>
class size class size
{ {
Line 61: Line 64:
} }
}; };
 +</pre>
This example shows how overriding in the owner can help a class to control the values assigned to its members. This example shows how overriding in the owner can help a class to control the values assigned to its members.
 +
 +
Overriding in owner class has the following requirements to participating classes: The first participating class (class A) must declare a public virtual function. The second participating class (class B) must provide a function override and include an object of class A as a member. The declaration of the override associates the name of the overridden function with the name of the member for which the override is done. New overriding has the following in common with the standard overriding of C++: Overriding in owner class has the following requirements to participating classes: The first participating class (class A) must declare a public virtual function. The second participating class (class B) must provide a function override and include an object of class A as a member. The declaration of the override associates the name of the overridden function with the name of the member for which the override is done. New overriding has the following in common with the standard overriding of C++:
-· When entering the body of override, this points to an instance of the overriding class (B), not of the original one (A). However, in our case these classes are not related through the mechanism of inheritance.+ 
-· The override is called not only when the original function is called directly on the member, but also when the original function is called on a pointer to, or reference to the member object, a pointer to one of the member's ancestors in the inheritance chain, or a pointer to one of the member's base classes in the multiple inheritance – in other words, when the exact type of the member is not known.+* When entering the body of override, ''this'' points to an instance of the overriding class (B), not of the original one (A). However, in our case these classes are not related through the mechanism of inheritance.
-· The function override is called instead of the original function, and therefore it must call the original function from its body, if it is not a full substitute. The call should be qualified with the name of the member’s class, to disable the virtual binding and prevent the override from getting called again. In addition, the call should be qualified with the name of the member itself (in our case, a.A::f(), not just A::f()), because an original function can only be called on an object belonging to the type of the member (A).+ 
-· A property of transitivity: a class can override not only the functions of its members, but also the functions of the members of its members. If we declare B::a::f() virtual and override it in the class C (suppose C can access methods of B):+* The override is called not only when the original function is called directly on the member, but also when the original function is called on a pointer to, or reference to the member object, a pointer to one of the member's ancestors in the inheritance chain, or a pointer to one of the member's base classes in the multiple inheritance – in other words, when the exact type of the member is not known.
 + 
 +* The function override is called ''instead'' of the original function, and therefore it must call the original function from its body, if it is not a full substitute. The call should be qualified with the name of the member’s class, to disable the virtual binding and prevent the override from getting called again. In addition, the call should be qualified with the name of the member itself (in our case, a.A::f(), not just A::f()), because an original function can only be called on an object belonging to the type of the member (A).
 + 
 +* A property of transitivity: a class can override not only the functions of its members, but also the functions of the members of its members. If we declare B::a::f() virtual and override it in the class C (suppose C can access methods of B):
 + 
 +<pre>
class C class C
{ {
Line 73: Line 85:
int b::a::f(); int b::a::f();
}; };
 +</pre>
then the following is true then the following is true
-b.a.f(); // C::b::a::f() is called+ b.a.f(); // C::b::a::f() is called
-b.a.B::a::f(); // B::a::f() is called+ b.a.B::a::f(); // B::a::f() is called
-b.a.A::f(); // A::f() is called+ b.a.A::f(); // A::f() is called
If f() is not overridden in the class B, expression If f() is not overridden in the class B, expression
-b.a.B::a::f();+ b.a.B::a::f();
is equivalent to b.a.A::f(). is equivalent to b.a.A::f().
 +
 +
Overriding in owner class is not simply the usual C++ overriding with the owner class playing the role of the derived class. There are some important differences: Overriding in owner class is not simply the usual C++ overriding with the owner class playing the role of the derived class. There are some important differences:
-· The overriding is done not for a class (A), but for a member of a class (B::a), that is, it does not affect any objects except the member.+ 
-· Only a function belonging to the public interface of the member's class can be overridden.+* The overriding is done not for a class (A), but for a member of a class (B::a), that is, it does not affect any objects except the member.
-· In the body of the function override, only the public interface of the member's class can be used. That is, overriding in owner class gives different access rights to its first participating class than the usual override. +* Only a function belonging to the public interface of the member's class can be overridden.
-· A class can use an abstract class for its member. In this case, it must use overriding in owner class to provide implementation for pure virtual functions of the member’s class.+* In the body of the function override, only the public interface of the member's class can be used. That is, overriding in owner class gives different access rights to its first participating class than the usual override.
 +* A class can use an abstract class for its member. In this case, it must use overriding in owner class to provide implementation for pure virtual functions of the member’s class.
 + 
Note, that we only consider the overriding of methods of a contained member. Overriding at the run time of methods of objects referred to by pointers initially looked very interesting. However, it turned out to be too complicated for the programs, because of its often unpredictable, extremely dynamic nature. I have left such applications outside of the scope of this article. In case of overriding for a contained member, the implementations of the overriding mechanism can rely on the exact type of member object, known at compile time, instead of relying on the dynamic dependencies at run-time. The override declaration is close to the member, making it easy to understand the relationship. Note, that we only consider the overriding of methods of a contained member. Overriding at the run time of methods of objects referred to by pointers initially looked very interesting. However, it turned out to be too complicated for the programs, because of its often unpredictable, extremely dynamic nature. I have left such applications outside of the scope of this article. In case of overriding for a contained member, the implementations of the overriding mechanism can rely on the exact type of member object, known at compile time, instead of relying on the dynamic dependencies at run-time. The override declaration is close to the member, making it easy to understand the relationship.
 +
Overriding in owner class is not extending or modifying the interface of the owner class. Function overrides belong to the interface of the member, not to the interface of the owner. For instance, B::a::f() is part of the interface of B::a, not B. It cannot be called from an object of class B. Hence, the following calls are syntactically incorrect: Overriding in owner class is not extending or modifying the interface of the owner class. Function overrides belong to the interface of the member, not to the interface of the owner. For instance, B::a::f() is part of the interface of B::a, not B. It cannot be called from an object of class B. Hence, the following calls are syntactically incorrect:
-b::a::f();+ 
-c.C::b::a::f();+ b::a::f();
 + c.C::b::a::f();
 + 
For the same reason, there is an additional rule: the access rights of the overrides should be the same as the access rights of the member for which they are done (overrides for a public member should be public, etc.). An implementation of overriding in owner class in C++ is described in the “Inside the Overriding Mechanism” section later in this article. It is relatively straightforward: it does not require special data structures, does not interfere with other language features, and does not lead to losses in efficiency or memory. The same mechanism of dynamic binding through virtual method tables is used for overriding in owner class as for the usual overriding. For the same reason, there is an additional rule: the access rights of the overrides should be the same as the access rights of the member for which they are done (overrides for a public member should be public, etc.). An implementation of overriding in owner class in C++ is described in the “Inside the Overriding Mechanism” section later in this article. It is relatively straightforward: it does not require special data structures, does not interfere with other language features, and does not lead to losses in efficiency or memory. The same mechanism of dynamic binding through virtual method tables is used for overriding in owner class as for the usual overriding.
'''Next: [[Applications of Overriding in Owner]]''' '''Next: [[Applications of Overriding in Owner]]'''

Revision as of 07:13, 3 February 2006

Consider a class A with a public virtual function f():

class A { 
public: 
	virtual int f();
};

Class B contains a member a belonging to class A:

class B {
	A a;
};

It is necessary to perform certain actions in B at the moment the user code calls method f() of its member B::a.

The mechanism of overriding in the owner class is an extension of polymorphism allowing a virtual function of class A to be overridden in class B which includes an object of A as a member.

According to this definition, f() can be overridden in class B

class B {
	A a;
	int a::f();
};

so that the following is true:

a.f(); // B::a::f() is called, not A::f()
…
A& r = a;
r.f(); // B::a::f() is called, not A::f()

Now every time the client calls f() on B::a, B is aware of it. B also has the possibility to adapt f()'s implementation to its own needs.

Example.

class size
{
	long value;
public:
	long get() { return value; }
	virtual void set(long l) { value == l; }
};

class lee_jeans
{
	size waist, inseam;

	void waist::set(long l) 
	{ 
		assert(l > 28 && l <= 36 ); 
		// call the original
		waist.size::set(l); 
	}	
	void inseam::set(long l) 
	{ 
		assert(l > 30 && l <= 42 ); 
		// call the original
		inseam.size::set(l); 
	}
};

This example shows how overriding in the owner can help a class to control the values assigned to its members.


Overriding in owner class has the following requirements to participating classes: The first participating class (class A) must declare a public virtual function. The second participating class (class B) must provide a function override and include an object of class A as a member. The declaration of the override associates the name of the overridden function with the name of the member for which the override is done. New overriding has the following in common with the standard overriding of C++:

  • When entering the body of override, this points to an instance of the overriding class (B), not of the original one (A). However, in our case these classes are not related through the mechanism of inheritance.
  • The override is called not only when the original function is called directly on the member, but also when the original function is called on a pointer to, or reference to the member object, a pointer to one of the member's ancestors in the inheritance chain, or a pointer to one of the member's base classes in the multiple inheritance – in other words, when the exact type of the member is not known.
  • The function override is called instead of the original function, and therefore it must call the original function from its body, if it is not a full substitute. The call should be qualified with the name of the member’s class, to disable the virtual binding and prevent the override from getting called again. In addition, the call should be qualified with the name of the member itself (in our case, a.A::f(), not just A::f()), because an original function can only be called on an object belonging to the type of the member (A).
  • A property of transitivity: a class can override not only the functions of its members, but also the functions of the members of its members. If we declare B::a::f() virtual and override it in the class C (suppose C can access methods of B):
class C 
{
	B b;
	int b::a::f();
};

then the following is true

b.a.f();		// C::b::a::f() is called
b.a.B::a::f();	// B::a::f() is called
b.a.A::f();		// A::f() is called

If f() is not overridden in the class B, expression

b.a.B::a::f();

is equivalent to b.a.A::f().


Overriding in owner class is not simply the usual C++ overriding with the owner class playing the role of the derived class. There are some important differences:

  • The overriding is done not for a class (A), but for a member of a class (B::a), that is, it does not affect any objects except the member.
  • Only a function belonging to the public interface of the member's class can be overridden.
  • In the body of the function override, only the public interface of the member's class can be used. That is, overriding in owner class gives different access rights to its first participating class than the usual override.
  • A class can use an abstract class for its member. In this case, it must use overriding in owner class to provide implementation for pure virtual functions of the member’s class.

Note, that we only consider the overriding of methods of a contained member. Overriding at the run time of methods of objects referred to by pointers initially looked very interesting. However, it turned out to be too complicated for the programs, because of its often unpredictable, extremely dynamic nature. I have left such applications outside of the scope of this article. In case of overriding for a contained member, the implementations of the overriding mechanism can rely on the exact type of member object, known at compile time, instead of relying on the dynamic dependencies at run-time. The override declaration is close to the member, making it easy to understand the relationship.

Overriding in owner class is not extending or modifying the interface of the owner class. Function overrides belong to the interface of the member, not to the interface of the owner. For instance, B::a::f() is part of the interface of B::a, not B. It cannot be called from an object of class B. Hence, the following calls are syntactically incorrect:

b::a::f();
c.C::b::a::f();

For the same reason, there is an additional rule: the access rights of the overrides should be the same as the access rights of the member for which they are done (overrides for a public member should be public, etc.). An implementation of overriding in owner class in C++ is described in the “Inside the Overriding Mechanism” section later in this article. It is relatively straightforward: it does not require special data structures, does not interfere with other language features, and does not lead to losses in efficiency or memory. The same mechanism of dynamic binding through virtual method tables is used for overriding in owner class as for the usual overriding.


Next: Applications of Overriding in Owner