2012-02-24 119 views
16
class base{ 
    ..... 
    virtual void function1(); 
    virtual void function2(); 
}; 

class derived::public base{ 
    int function1(); 
    int function2(); 
}; 

int main() 
{ 
    derived d; 
    base *b = &d; 
    int k = b->function1() // Why use this instead of the following line? 
    int k = d.function1(); // With this, the need for virtual functions is gone, right? 

} 

我不是CompSci工程師,我想知道這一點。爲什麼使用虛函數,如果我們可以避免基類指針?爲什麼使用派生類的基類指針

回答

47

多態性的力量並不是真正的appa租你的簡單例子,但如果你擴展一點它可能會變得更清晰。

class vehicle{ 
     ..... 
     virtual int getEmission(); 
} 

class car : public vehicle{ 
     int getEmission(); 
} 

class bus : public vehicle{ 
     int getEmission(); 
} 

int main() 
{ 
     car a; 
     car b; 
     car c; 
     bus d; 
     bus e; 

     vehicle *traffic[]={&a,&b,&c,&d,&e}; 

     int totalEmission=0; 

     for(int i=0;i<5;i++) 
     { 
      totalEmission+=traffic[i]->getEmission(); 
     } 

} 

這使您可以遍歷指針列表並根據基礎類型調用不同的方法。基本上它可以讓你編寫代碼,你不需要知道在編譯時子類型是什麼,但代碼無論如何都會執行正確的功能。

+6

這可能是使用虛函數的最好例子之一。謝謝! – Garfield 2013-03-05 06:16:42

+0

明智的答案,但是當我已經知道必須爲所有這些類對象添加排放時,爲什麼我不能手動創建'car'和'bus'的對象並正常添加它們?爲什麼我需要基類類型指針。 – Yankee 2017-09-14 13:10:39

+0

假設如果我們不使用虛函數,那麼使用派生類的基類指針有什麼好處? – Rajesh 2017-09-26 17:07:42

4

你是對的,如果你有一個對象,你不需要通過指針來引用它。當對象按照創建的類型銷燬時,您也不需要虛擬析構函數。

該實用程序出現在您從另一段代碼獲取指向對象的指針時,並且您不知道最派生類型是什麼。您可以在同一個基礎上構建兩個或更多個派生類型,並且具有返回指向基本類型的指針的函數。虛擬函數將允許您使用指針,而不用擔心您使用的是哪種派生類型,直到有時間銷燬該對象。虛擬析構函數將銷燬對象而不知道它與哪個派生類相對應。

下面是使用虛擬功能的最簡單的例子:

base *b = new derived; 
b->function1(); 
delete b; 
+1

我認爲他的問題是,爲什麼要用基類指針,而不是爲什麼虛析構函數 – 2012-02-24 05:43:32

1

其實現多態性。除非你有指向派生對象的基類指針 ,否則在這裏你不能擁有多態。

One of the key features of derived classes is that a pointer to a derived class is type-compatible with a pointer to its base class. Polymorphism is the art of taking advantage of this simple but powerful and versatile feature, that brings Object Oriented Methodologies to its full potential.

In C++, a special type/subtype relationship exists in which a base class pointer or a reference can address any of its derived class subtypes without programmer intervention. This ability to manipulate more than one type with a pointer or a reference to a base class is spoken of as polymorphism.

Subtype polymorphism allows us to write the kernel of our application independent of the individual types we wish to manipulate. Rather, we program the public interface of the base class of our abstraction through base class pointers and references. At run-time, the actual type being referenced is resolved and the appropriate instance of the public interface is invoked. The run-time resolution of the appropriate function to invoke is termed dynamic binding (by default, functions are resolved statically at compile-time). In C++, dynamic binding is supported through a mechanism referred to as class virtual functions. Subtype polymorphism through inheritance and dynamic binding provide the foundation for objectoriented programming

The primary benefit of an inheritance hierarchy is that we can program to the public interface of the abstract base class rather than to the individual types that form its inheritance hierarchy, in this way shielding our code from changes in that hierarchy. We define eval(), for example, as a public virtual function of the abstract Query base class. By writing code such as _rop->eval(); user code is shielded from the variety and volatility of our query language. This not only allows for the addition, revision, or removal of types without requiring changes to user programs, but frees the provider of a new query type from having to recode behavior or actions common to all types in the hierarchy itself. This is supported by two special characteristics of inheritance: polymorphism and dynamic binding. When we speak of polymorphism within C++, we primarily mean the ability of a pointer or a reference of a base class to address any of its derived classes. For example, if we define a nonmember function eval() as follows, // pquery can address any of the classes derived from Query void eval(const Query *pquery) { pquery->eval(); } we can invoke it legally, passing in the address of an object of any of the four query types:

int main() 
{ 
AndQuery aq; 
NotQuery notq; 
OrQuery *oq = new OrQuery; 
NameQuery nq("Botticelli"); // ok: each is derived from Query 
// compiler converts to base class automatically 
eval(&aq); 
eval(&notq); 
eval(oq); 
eval(&nq); 
} 

而試圖調用與對象的地址的eval()從查詢 導致編譯時錯誤不衍生自:

int main() 
{ string name("Scooby-Doo"); // error: string is not derived from Query 
eval(&name); 
} 

Within eval(), the execution of pquery->eval(); must invoke the appropriate eval() virtual member function based on the actual class object pquery addresses. In the previous example, pquery in turn addresses an AndQuery object, a NotQuery object, an OrQuery object, and a NameQuery object. At each invocation point during the execution of our program, the actual class type addressed by pquery is determined, and the appropriate eval() instance is called. Dynamic binding is the mechanism through which this is accomplished. In the object-oriented paradigm, the programmer manipulates an unknown instance of a bound but infinite set of types. (The set of types is bound by its inheritance hierarchy. In theory, however, there is no limit to the depth and breadth of that hierarchy.) In C++ this is achieved through the manipulation of objects through base class pointers and references only. In the object-based paradigm, the programmer manipulates an instance of a fixed, singular type that is completely defined at the point of compilation. Although the polymorphic manipulation of an object requires that the object be accessed either through a pointer or a reference, the manipulation of a pointer or a reference in C++ does not in itself necessarily result in polymorphism. For example, consider

// no polymorphism 
    int *pi; 
// no language-supported polymorphism 
    void *pvi; 
// ok: pquery may address any Query derivation 
    Query *pquery; 

In C++, polymorphism exists only within individual class hierarchies. Pointers of type void* can be described as polymorphic, but they are without explicit language support — that is, they must be managed by the programmer through explicit casts and some form of discriminant that keeps track of the actual type being addressed.

+0

最後一部分是從C++底漆!拿到那本書並讀入多形態 – 2012-02-24 05:59:38

0

你好像問了兩個問題(標題和結尾):

  1. 爲什麼要用基類指針派生類的? 這是多態性的使用。它允許您在統一處理對象的同時允許您具體實現。如果這讓你感到困擾,那麼我認爲你應該問:爲什麼多態?

  2. 爲什麼使用虛擬析構函數,如果我們可以避免基類指針? 這裏的問題是你不能總是避免使用基類指針來利用多態性的強度。

相關問題