Dennis’s Weblog

Archive for the ‘Language Research’ Category

In Section 24.7, we discussed multiple inheritance, the process by which one class inherits from two or more classes. Multiple inheritance is used, for example, in the C++ standard library to form class basic_iostream (Fig. 24.12).

figure 24.12

Fig. 24.12 Multiple inheritance to form class basic_iostream. Class basic_ios is the base class for both basic_istream and basic_ostream, each of which is formed with single inheritance. Class basic_iostream inherits from both basic_istream and basic_ostream. This enables objects of class basic_iostream to provide the functionality of both basic_istreams and basic_ostreams. In multiple-inheritance hierarchies, the situation described in Fig. 24.12 is referred to as diamond inheritance. Because classes basic_istream and basic_ostream each inherit from basic_ios, a potential problem exists for basic_iostream. Class basic_iostream could contain two copies of the members of class basic_ios—one inherited via class basic_istream and one inherited via class basic_ostream). Such a situation would be ambiguous and would result in a compilation error, because the compiler would not know which version of the members from class basic_ios to use. Of course, basic_iostream does not really suffer from the problem we mentioned. In this section, you will see how using virtual base classes solves the problem of inheriting duplicate copies of an indirect base class.

Compilation Errors Produced When Ambiguity Arises in Diamond Inheritance

Figure 24.13 demonstrates the ambiguity that can occur in diamond inheritance. The program defines class Base (lines 9–13), which contains pure virtual function print (line 12). Classes DerivedOne (lines 16–24) and DerivedTwo (lines 27–35) each publicly inherit from class Base and override the print function. Class DerivedOne and class DerivedTwo each contain what the C++ standard refers to as a base-class subobject—i.e., the members of class Base in this example.

 1  // Fig. 24.13: fig24_13.cpp
 2  // Attempting to polymorphically call a function that is
 3  // multiply inherited from two base classes.
 4  #include <iostream>
 5  using std::cout;
 6  using std::endl;
 7
 8  // class Base definition
 9  class Base
10  {
11  public:
12     virtual void print() const = 0; // pure virtual
13  }; // end class Base
14
15  // class DerivedOne definition
16  class DerivedOne : public Base
17  {
18  public:
19     // override print function
20     void print() const
21     {
22        cout << "DerivedOne\n";
23     } // end function print
24  }; // end class DerivedOne
25
26  // class DerivedTwo definition
27  class DerivedTwo : public Base
28  {
29  public:
30     // override print function
31     void print() const
32     {
33        cout << "DerivedTwo\n";
34     } // end function print
35  }; // end class DerivedTwo
36
37  // class Multiple definition
38  class Multiple : public DerivedOne, public DerivedTwo
39  {
40  public:
41     // qualify which version of function print
42     void print() const
43     {
44        DerivedTwo::print();
45     } // end function print
46  }; // end class Multiple
47
48  int main()
49  {
50     Multiple both; // instantiate Multiple object
51     DerivedOne one; // instantiate DerivedOne object
52     DerivedTwo two; // instantiate DerivedTwo object
53     Base *array[ 3 ]; // create array of base-class pointers
54
55     array[ 0 ] = &both; // ERROR--ambiguous
56     array[ 1 ] = &one;
57     array[ 2 ] = &two;
58
59     // polymorphically invoke print
60     for ( int i = 0; i < 3; i++ )
61        array[ i ] -> print();
62
63     return 0;
64  } // end main
 Fig. 24.13  Attempting to call a multiply inherited function polymorphically.

 

Output

 C:\Projects\cpphtp5\examples\ch24\Fig24_20\Fig24_20.cpp(55): error C2594:
 '=' : ambiguous conversions from 'Multiple *' to 'Base *'

Class Multiple (lines 38–46) inherits from both classes DerivedOne and DerivedTwo. In class Multiple, function print is overridden to call DerivedTwo’s print (line 44). Notice that we must qualify the print call with the class name DerivedTwo to specify which version of print to call.

Function main (lines 48–64) declares objects of classes Multiple (line 50), DerivedOne (line 51) and DerivedTwo (line 52). Line 53 declares an array of Base * pointers. Each array element is initialized with the address of an object (lines 55–57). An error occurs when the address of both—an object of class Multiple—is assigned to array[ 0 ]. The object both actually contains two subobjects of type Base, so the compiler does not know which subobject the pointer array[ 0 ] should point to, and it generates a compilation error indicating an ambiguous conversion

. Multiple Inheritance and virtual Base Classes (Continued)

Eliminating Duplicate Subobjects with virtual Base-Class Inheritance

The problem of duplicate subobjects is resolved with virtual inheritance. When a base class is inherited as virtual, only one subobject will appear in the derived class—a process called virtual base-class inheritance. FFigure 24.14 revises the program of Fig. 24.13 to use a virtual base class.

 1  // Fig. 24.14: fig24_14.cpp
 2  // Using virtual base classes.
 3  #include <iostream>
 4  using std::cout;
 5  using std::endl;
 6
 7  // class Base definition
 8  class Base
 9  {
10  public:
11     virtual void print() const = 0; // pure virtual
12  }; // end class Base
13
14  // class DerivedOne definition
15  class DerivedOne : virtual public Base
16  {
17  public:
18     // override print function
19     void print() const
20     {
21        cout << "DerivedOne\n";
22     } // end function print
23  }; // end DerivedOne class
24
25  // class DerivedTwo definition
26  class DerivedTwo : virtual public Base
27  {
28  public:
29     // override print function
30     void print() const
31     {
32        cout << "DerivedTwo\n";
33     } // end function print
34  }; // end DerivedTwo class
35
36  // class Multiple definition
37  class Multiple : public DerivedOne, public DerivedTwo
38  {
39  public:
40     // qualify which version of function print
41     void print() const
42     {
43        DerivedTwo::print();
44     } // end function print
45  }; // end Multiple class
46
47  int main()
48  {
49     Multiple both; // instantiate Multiple object
50     DerivedOne one; // instantiate DerivedOne object
51     DerivedTwo two; // instantiate DerivedTwo object
52
53     // declare array of base-class pointers and initialize
54     // each element to a derived-class type
55     Base *array[ 3 ];
56     array[ 0 ] = &both;
57     array[ 1 ] = &one;
58     array[ 2 ] = &two;
59
60     // polymorphically invoke function print
61     for ( int i = 0; i < 3; i++ )
62        array[ i ]->print();
63
64     return 0;
65  } // end main
 Fig. 24.14  Using virtual base classes.

Output

DerivedTwo
DerivedOne
DerivedTwo

The key change in the program is that classes DerivedOne (line 15) and DerivedTwo (line 26) each inherit from class Base by specifying virtual public Base. Since both of these classes inherit from Base, they each contain a Base subobject. The benefit of virtual inheritance is not clear until class Multiple inherits from both DerivedOne and DerivedTwo (line 37). Since each of the base classes used virtual inheritance to inherit class Base’s members, the compiler ensures that only one subobject of type Base is inherited into class Multiple. This eliminates the ambiguity error generated by the compiler in Fig. 24.13. The compiler now allows the implicit conversion of the derived-class pointer (&both) to the base-class pointer array[ 0 ] at line 56 in main. The for statement at lines 61–62 polymorphically calls print for each object.

Constructors in Multiple-Inheritance Hierarchies with virtual Base Classes

Implementing hierarchies with virtual base classes is simpler if default constructors are used for the base classes. The examples in Fig. 24.13 and Fig. 24.14 use compiler-generated default constructors. If a virtual base class provides a constructor that requires arguments, the implementation of the derived classes becomes more complicated, because the most derived class must explicitly invoke the virtual base class’s constructor to initialize the members inherited from the virtual base class.

Reference: http://www.deitel.com/articles/cplusplus_tutorials/20060225/virtualBaseClass/

Advertisements

OO Principle:

Favor composition over Inheriance;

When we first learn OOP, We know Inheriance. With it, we can reuse the code by extend it. Later we know we spend much more time extent and maintain the code than reuse the code. When you use inheriance, the relationship is “Is A”, In other words, the extended object are actually a superclass object. They have the same fields and methods. With the use of these methods, we can reuse the oringinal code.

But when we would like to maintain the code and add some new functions, problems come out. Once you want to add new feature to a existed class, you should update all the existed class, and this cause a nightmare.

Since that there is a OO principle: prefer composition to inheritance.  Composition means the relationship is “HAS A”. The merit of inheriance is reuse. When we use composition we can have such a merit by contain a superclass object but not inherit it. With this contained superclass object, we can still reuse the super class code to implement and add new features to our new object.

At the same time, In C++, there is a feature: multiple inheritance. That means a class can inherit mutiple class ‘s features and reuse their code. How can we implement such a function with our language ? Yup, we can contain mutiple objects which have the features that we want to inherit, and then we can have their functions. Futhermore, if these object that we want to inherit have something common, then we  can define a interface, and all the “superclass” that we want to contain should implement this interface. And then we can use such a common interface in our inherited class to process all the “superclass”, for example, we can have add() or remove() functions which can add or remove the superclass features.(the Duck example in Head first Design patterns)

Each class know other class only the common interface, once one of them changed will not affect the other class! That’s what we said: loosely coupled OO Design Principle.

  Read the rest of this entry »

  1. Interfaces are essentially having all method prototypes no definition but Abstract class can contain method definations also.
  2. In short Interface is a abstract class having all methods abstract.
  3. Both abstract classes and interfaces are used when there is a difference in behaviour among the sub-types extending the abstract class or implementing the interface.
  4. When the sub-types behaviour is totally different then you use an interface, when the sub-types behaviour is partially common and different with respect to the supertype an abstract class is used. In an abstract class the partially common behaviour is given a concrete implementation. Since there is no common behaviour between an interface and a sub-type an interface does not have an implementation for any of its behaviour.           Here is the point when we want to encapsulate the varies, we should meditate on selecting which struct.
  5. If you create a abstract class writing the abstract keyword in the declaration part then You only can inherit the class. You can not create an instance of this abstract class but can inherit the class and with creating the instance of the derived class you can access the method of the abstract class.
  6. If you use a virtual keyword in a method then you can override this method in the subclass if you wish..
  7. If you create a abstract method then you must override this method in the subclass other wise it shows error in the program.
  8. Abstract class will may or may not contain contructor while interface will not.

references:

a. When to use override and new keywords(http://msdn.microsoft.com/en-us/library/ms173153(VS.80).aspx);

b.virtual keyword:

When a virtual method is invoked, the run-time type of the object is checked for an overriding member. The overriding member in the most derived class is called, which might be the original member, if no derived class has overridden the member.

By default, methods are non-virtual. You cannot override a non-virtual method. So when you call the method  though the dynamic call(superclass), it will still call the original function. But not dynamically call the function corresponding to the type of the object.

You cannot use the virtual modifier with the static, abstract, private or override modifiers.

Virtual properties behave like abstract methods, except for the differences in declaration and invocation syntax.

  • It is an error to use the virtual modifier on a static property.
  • A virtual inherited property can be overridden in a derived class by including a property declaration that uses the override modifier.

The implementation of a virtual member can be changed by an overriding member in a derived class. For more information on using the virtual keyword, see Versioning with the Override and New Keywords (C# Programming Guide) and Knowing When to Use Override and New Keywords (C# Programming Guide).

C:

class A
{
public void  hello()
{
System.Console.Out.WriteLine(“I am A”);
}
}
class B : A
{
public void hello()//It will prompt you to use “NEW” keyword to conceal the A::hello(), but if you miss out “NEW”, it’s the same !!!!
{
System.Console.Out.WriteLine(“I am B”);
}
}

//Main in C#