`

c++ - virtual inheritance

    博客分类:
  • c++
c++ 
阅读更多

As we have discussed in the post - c++ type of inheritance, we have covered private inheritance (a.k.a ) implementation inheritance, protected inheritance and public inheritance (a.k.a type inheritance). In this topic we are going to discuss virutal inheritance.

 

However, called virtual inheritance, it does not have close relationship with the private/protected/public inheritance. virtual inheritance is often used in the cases where multiple inheritance hierarichy is used. 

 

 

For our discussion, let's first see an class hierarchy. 

 

 

hierarchy_example 1

               ZooAnimal                                 Endangered
            /            \                                /
         -V-              -V-                            /
        /                   \                           /
     Bear                   Racoon                    /
           \                   \                     /
            ------------\       \                   /
                         \       \       --------- /
                          \       \     /    
                          ------  Panda

 

ZooAnimal is a virtual base class of Raccon and Bear. 

 

Before we dive into the virtual inheritance, let's first examine the problem without virtual base/inheritance.

 

 

 

C++ is a language which supports multiple inheritance. We have learned that when a class subclass another class, the super class become a subobject of the derived class, suppose if through multiple inheritance tree, a class appears twice on both side, then it has some problem this has two implications

  1. it waste spaces

  2. a more serious problem is ambiguity, which member method/data object to call?

 

virtual inhertiance is just to address the issue we have identified earlier.  under virtual inheritance:  there is only a single, shared base class subobject is inherited regardless of how many times the base class occurs within the derivation hierarchy.

 

so the importance of virtual inheritance under multiple inhertiance is said, let see some code examples. 

 

 

/*
* ZooAnimal to support a void paramter constructor
*/
class ZooAnimal {

public:
	ZooAnimal(string name, bool onExhibit, string fam_name) : _name(name), _onExhibit(onExhibit), _fam_name(fam_name) {}
        // We will see under what situation we need a void parameter ctor
	// ZooAnimal() : _name(NULL), _onExhibit(false), _fam_name(NULL) {}

	virtual ~ZooAnimal();
	virtual ostream& print (ostream &) const; 
	string name() const { return _name; } 
	string family_name() const { return _fam_name; } 
private:
protected:
	bool _onExhibit;
	string _name;
	string _fam_name;
} ;
 
then the Bear 

class Bear: public virtual ZooAnimal { 
public:
	enum DanceType { two_left_feet, macarena, fandango, waltz } ;
	Bear(string name, bool onExhibit= true) : ZooAnimal(name, onExhibit, "Bear") , _dance(two_left_feet)
	{}
	virtual ostream & print(ostream& ) const; 
	void dance(DanceType );
private:
protected:
	DanceType _dance;
};
 then The Raccoon

class Raccoon : virtual public ZooAnimal { 
public:
	Raccoon(string name, bool onExhibit = true) : ZooAnimal(name, onExhibit, "Raccoon"), _pettable(false) {}
	virtual ostream& print(ostream& ) const;
	bool pettable() const { return _pettable; }
	void pettable(bool petval) { _pettable = petval; } 
private:
protected:
	bool _pettable;
};
 
followed by Endangered
class Endangered
{
public:
	enum CriticalLevel { critical, high, low, trivial };
	enum EndangeredCause { environment, population } ;


	Endangered(EndangeredCause cause, CriticalLevel level) : _cause(cause), _level(level) { }
private:
protected:
	CriticalLevel _level;
	EndangeredCause _cause;
};
 Last is the Panda 
class Panda : public Bear, public Raccoon, public Endangered 
{
public: 
	Panda(string name, bool onExhibit = true) ;
	virtual ostream& print(ostream &) const; 

	bool sleeping () const { return _sleeping; } 

private:
protected:
	bool _sleeping;
};
 

Special Initialization Semantics

You may have noticed that the Pand class does not have the constructor defined.  The initialization in virtual base cases is different from what it is in single hierarchy case.  Let's examine our Panda case. 

when a Panda object is initialized , (1) the explicit nvocation of the ZooAnimal constructor within Raccoon and Bear are no loger executed  during the execution and (2) the ZooAnimal constructor is invoked with the arguments specified for the ZooAnimal constructors in the initialization
list of the Panda constructor,

within Panda, both the Bear and Raccoon classes serve as intermediates rather as the most derived class, As an intermediate derived class, direct invocation of all virtual  base class constructor are suppresessed automatically. Were panda subsequently derived from, then Panda itself would become  an inermediate class of the derived class object, 


with this in mind, let' s see the constructor code below. 

Panda::Panda(string name, bool onExhibit) : ZooAnimal (name, onExhibit, "Panda"),
											Bear(name, onExhibit),
											Raccoon(name, onExhibit), 
											Endangered(Endangered::environment, 
											Endangered::critical),
											_sleeping(false)
{
}
 
We may come back to order of virtual base initialization, but first let's first  check the code of ctor, Bear and Raccoon just simply pass on/carry the name and onExhibit arguments to its base class when they are serving as the intermediate derived class . So, there is excessive call, a different design, by modifying the ctor of Bear/Raccon is as follow 


class Bear: public virtual ZooAnimal { 
public:

	Bear(string name, bool onExhibit= true) : ZooAnimal(name, onExhibit, "Bear") , _dance(two_left_feet)
	{}
protected:
	// when an intermediate derived class
	Bear() : _dance( two_left_feet) {}
        // rest are the same..
};
 you may modify the ZooAnimal slight bit to have an empty protected argument list constructor 
class ZooAnimal {
protected:
	ZooAnimal() : _name(NULL), _onExhibit(false), _fam_name(NULL) {}

} ;
 you can do the same to Raccoon, after the modification, you can modify the ctor of Panda as such . 

Panda::Panda(string name, bool onExhibit) : ZooAnimal (name, onExhibit, "Panda"),
											Endangered(Endangered::environment, 
											Endangered::critical),
											_sleeping(false)
{
}
 
Neater, isn't it? 

Construcotr and destructor order

Given a inheritance tree, where virtual base classes can appear in more than one inheritance subtree.

So, as usual, I will give a inheritance tree is as followe to allow us to describe what we can achieve.

/** 
* hierarchy_example 2
*
*    Character      ZooAnimal      ToyAnimal
*       ^               ^             ^
*       |               v            v
*       |               |           /
*    RockCharacter   Bear          /
*          ^            ^         /
*          |            |        /
*          \           /   --- -
*            \       /   /      
*             TdeddyBear
*
*/

/*
*  there is a  basic rule in terms the order of the Constructor and Destructor Order
*   Virtual base classes are always constructed prior to to nonvirutal base classes regardless where they appear in the inheritance hierarchy. 
*  Let's see the example above, we are going to illustrate the discussion we have seen before.
* 
*/
class Character {} ;
class BookCharacter : public Character { };
class ToyAnimal { } 
class TeddyBear : public BookCharacter, public Bear, public virtual ToyAnimal 
{

};
 
The immediate base classes are examined in the order of their declaration for the presence of virutal base calsses.

In our example, the inheritance  subtree of BookCharacter is examined first, then that of Bear,  and finally that of ToyAnimal, Each subtreee is examined in depth first, tat is the sarch begins   first with the root classes and moves down. For the BookCharacter subtree, first Charcter, then BookCharacter are examined . For the Bear Subtree, first ZooAnimal, then Bear are examined.   

The order of virtual base class constructor are nvoked. the nonvirtual base classes constructors are invoked in the order of declaration.: BookCharacter then Bear. Prior to execution of the BookCharacter , its base Character constructor is invoked. 
 
 Given the declaration 

   TeddyBear Paggington;
it will call the consturctor as follow. 

  ZooAnimal();
 ToyAnimal();
  Character()
 BookCharacter()
 Bear();
 TeddyBear()
 


分享到:
评论

相关推荐

    面向对象程序设计语言C++--电子教案

    C++通过虚函数(Virtual Functions)和纯虚函数(Pure Virtual Functions)实现多态,使得基类指针或引用可以调用派生类的重写方法。 封装是将数据和操作数据的方法绑定在一起,对外部隐藏内部实现细节。C++通过...

    入门组C++(CSP2019-junior-C++-A).pdf

    面向对象编程主要包括类(class)、对象(object)、继承(inheritance)、多态(polymorphism)等概念。 #### 1. 类与对象 - **类**:是一种用户自定义的数据类型,它可以包含数据成员和成员函数。 - **对象**:是类的一...

    Inside the C++ Object Model

    oriented programming within C++: constructor semantics, temporary generation, support for encapsulation, inheritance, and "the virtuals"-virtual functions and virtual inheritance. This book shows how ...

    C++- 抽象类(存虚函数)、接口、多重继承1

    在C++中,使用虚继承(virtual inheritance)可以解决这个问题。 在给定的代码示例中,`Derived` 类从 `BaseA` 和 `BaseB` 多重继承,导致了指针 `pa` 和 `pb` 的地址不同。这是因为在内存布局中,`Derived` 对象...

    Inside the C++ Object Model_english&chinese;

    inheritance, and "the virtuals"-virtual functions and virtual inheritance. This book shows how your understanding the underlying implementation models can help you code more efficiently and with ...

    C++对象模型

    oriented programming within C++: constructor semantics, temporary generation, support for encapsulation, inheritance, and "the virtuals"-virtual functions and virtual inheritance. This book shows how ...

    Inside the C++ object model 高清英文版

    oriented programming within C++: constructor semantics, temporary generation, support for encapsulation, inheritance, and "the virtuals"-virtual functions and virtual inheritance. This book shows how ...

    inheritance---derived-class.rar_inheritance

    "inheritance---derived-class.rar_inheritance"这个压缩包文件显然包含了关于C++继承和派生类的详细教程。 继承的概念在于,子类可以自动获取基类的所有公共成员(包括数据成员和成员函数),并且可以添加新的成员...

    Inside the C++ object model

    oriented programming within C++: constructor semantics, temporary generation, support for encapsulation, inheritance, and "the virtuals"--virtual functions and virtual inheritance. This book shows how...

    C++面试-sizeof

    virtual void f() { cout ; } }; class Son : public Base { public: void f() { cout ; } }; int _tmain(int argc, _TCHAR* argv[]) { Base b; Son s; int size_b = sizeof(b); int size_s = sizeof(s); ...

    C++面试-cast

    ### 知识点一:C++中的reinterpret_cast `reinterpret_cast` 是C++中的一种类型转换操作符,它允许程序员将一种类型的指针重新解释为另一种类型的指针。这种转换在底层上通常涉及到对指针值的直接修改,并不涉及...

    C++ 中virtual 虚函数用法深入了解

    二、虚继承(Virtual Inheritance) 虚继承在派生类继承多个有共同基类时特别有用,可以避免“菱形问题”(即多重继承时可能出现的二义性)。以下是一个示例: ```cpp class Person { public: Person() { cout ...

    C++小游戏--贪吃蛇

    - 继承(inheritance),可能创建一个基类GameObject,然后让Snake和Food继承它,共享公共属性和行为。 - 封装(encapsulation),通过设置访问修饰符保护对象的内部状态,只允许通过特定接口进行修改。 - 多态...

    C++ 程序员学习过程

    - 学习 C++ 的核心概念,如类(class)、对象(object)、继承(inheritance)等。 - 理解 C++ 中的关键特性,包括友元(friend)、虚函数(virtual)/运行时类型识别(RTTI)、const 和 mutable 关键字、异常(exception)处理...

    Visual C++面向对象编程教程--王育坚

    C++通过虚函数(virtual functions)和纯虚函数(pure virtual functions)实现多态性,使得基类指针或引用可以调用派生类的重写方法。 除了以上核心概念,Visual C++环境还提供了一些额外的工具和特性,如MFC...

    实现C++类的多重继承

    C++默认采用二义性解析,可以通过虚继承(virtual inheritance)来解决。 5. **虚继承(Virtual Inheritance)** 虚继承通过在基类前加上`virtual`关键字来实现,可以消除钻石问题。这样,派生类只有一个共享的...

    面向对象程序设计---C++语言描述 原书第2版

    在C++中,可以通过虚函数(Virtual Function)实现运行时多态。 4. **封装**:封装是将数据成员和成员函数组合在一个单独的单元——类中,并控制外部对它们的访问程度,以保护数据的完整性和安全性。 #### C++语言...

Global site tag (gtag.js) - Google Analytics