2015-07-22 90 views
5

我有一個基本類的幾何對象,我自己使用,但我也想繼承這個類到另一個類的高級版本的對象,因爲他們共享了很多的邏輯。基礎對象有幾個靜態創建方法(由於參數衝突不能使用new),我不想繼承這些方法。我可以指定那些不被繼承嗎?你可以使一個類的方法不可繼承嗎?

編輯:包括一個例子

struct Banana { 
    float length; 

    Banana() {} 

    Banana(float length) { 
     this->length = length; 
    } 

    static Banana CreateByHalfLength(float halfLength) { 
     return Banana(halfLength * 2); 
    } 
}; 

struct AdvancedBanana : Banana { 
    float bendAmt; 

    AdvancedBanana(float length, float bendAmt) { 
     this->length = length; this->bendAmt = bendAmt; 
    } 
}; 

我不想AdvancedBanana :: CreateByHalfLength存在,而我也想香蕉:: CreateByHalfLength存在,並且是從類的外部訪問。

+0

這實際上會做什麼?我猜你想'Derived :: constructBase(args,go,here)'不起作用? (如果'constructBase'是'Base'上的靜態方法,'Derived'擴展'Base') – immibis

+1

如果我保留它,它會創建一個基礎對象實例。它真的沒有什麼傷害,只是令人困惑。此外,這些方法被稱爲「CreateByXYZWLH」或「CreateByRxRy」等,這些也適用於派生類,所以我可能想重用名稱。 – user81993

+0

@immibis答案看起來很直截了當。如果我沒有錯,如何使用私人關鍵字? – Nabin

回答

3

試試這個redclare功能爲私有的孩子:

#include <iostream> 
    class Banana { 
    public: 
     float length; 
     float getLenght(){ 
      return length; 
     } 
     void setLenght(float value){ 
      length = value; 
     } 
     Banana() {} 

     Banana(float length) { 
      this->length = length; 
     } 

     static Banana CreateByHalfLength(float halfLength) { 
      return Banana(halfLength * 2); 
     } 
    }; 

    class AdvancedBanana : public Banana { 
    public: 
     float bendAmt; 

     AdvancedBanana(float length, float bendAmt) { 
      this->length = length; this->bendAmt = bendAmt; 
     } 
    private: 
     static AdvancedBanana CreateByHalfLength(float halfLength); 

    }; 
    int main() 
    { 
    // work 
     Banana a(1); 
     a.CreateByHalfLength(1); 

    AdvancedBanana b(0,1); 
    //will fail 
    // b.CreateByHalfLength(1); 

    }; 
-1

你說的有點含糊,一個例子會很有用。 特別是由於您使用了單詞static,並且不清楚它的上下文是什麼。

您無法停止派生類繼承基類的所有方法。你可以做的最好的事情是讓它成爲一個非基礎對象參數的成員。然後,你必須在打電話之前貶低對象,但你仍然可以調用它。

你的建議似乎違反了Liskov替代原則。這意味着你應該重新考慮你的設計。

而不是B從A繼承。您可能需要A和B都從其派生的基類Q. [1]

[1] Q是一個笑話,一些聖經學者認爲有一些常見的不合適的書,他們稱之爲Q,每個福音書都被複制。

編輯:其他。

舉例說明一些事情更清楚。 讓我對你對C++的理解做一些基本的修正。你說過,由於參數衝突,你有幾種靜態創建方法。我認爲更好的說超載不能解決不同的施工方法。答案很簡單:以兩種方式之一擴展超載。 使用枚舉或使用類。 首先你可以看到流通過附加IOS調用讀/添加/讀寫型流::吃等

你的情況:

enum BCT {halfLength,fullLength,quarterLength ...}; 

那就不要 靜態香蕉創建(浮動尺寸,BCT類型= fullLength){ switch(type) case {fullLength:return Banana(size); case halfLength:return Banana(size * 2); case quarterLength:return Banana(size * 4); ... }}

了另一個版本是使用類區分參數類型(我相信詹姆斯Coplien稱這些範例)

class FullLength 
class HalfLength 
class QuarterLength 

然後:

static Banana Create(float length); // Full length 
static Banana Create(float halfLength, HalfLength &dummy); 
static Banana Create(float quarterlength, QuarterLength &dummy); 

新類不會在開銷中添加任何內容,但可以消除過載歧義。我相信boost/std :: filesystem使用這種方式來實現它的直接迭代器。

話雖如此,一旦你決定如何創建實例,這些不一定是靜態成員。他們可以是普通的構造函數,這將解決您的問題。大部分。您仍然無法阻止AdvancedBanana實施半長的創建方法,但編碼人員會意識到他正在執行此操作。

約靜的簡要說明,靜態成員函數是不訪問指針或者是什麼的一些語言調用自我,即它們不訪問特定實例的成員的。事實上,在preC++ 98天之前,在他們有靜力學之前,人們所做的是做類似的事情:((Banana *)NULL)->static_function(arguments);

在你的例子中,最好先使用構造函數。靜態構造函數更適合像工廠那樣真正需要的東西。

此外,在Mido的迴應中,a.CreateByHalfLength(1);這一行可能會或可能不會被編譯,我使用了很多很多的語言,有時我會被非法的東西弄糊塗(但是會顯示錯誤的想法。是香蕉:: CreateByHalfLength(1);不依賴於一個實例

1

你只能做到這樣,使用私有繼承AdvancedBanana。

#include <stdio.h> 

struct Banana { 
    float length; 

    Banana() {} 

    Banana(float length) { 
     this->length = length; 
    } 

    static Banana CreateByHalfLength(float halfLength) { 
     return Banana(halfLength * 2); 
    } 
}; 

struct AdvancedBanana : private Banana { 
    float bendAmt; 

    AdvancedBanana(float length, float bendAmt) { 
     this->length = length; this->bendAmt = bendAmt; 
    } 
}; 


int main() 
{ 
    Banana b; 
    b.CreateByHalfLength(1); 

    AdvancedBanana bb(1, 2); 
    //bb.CreateByHalfLength(2); 

    return 0; 
} 

如果您希望Banana :: CreateByHalfLength存在並且可以從課程外部訪問,AdvancedBanana :: CreateByHalfLength應該存在。 而且這也不是一個好的解決方案。

另一種方式,我建議,設計兩個或更多的班,或從香蕉功能,爲您的需求。這將是這樣的。

#include <stdio.h> 

struct Banana { 
    float length; 

    Banana() {} 

    Banana(float length) { 
     this->length = length; 
    } 
}; 

static Banana CreateByHalfLength(float halfLength) { 
    return Banana(halfLength * 2); 
} 

struct AdvancedBanana : private Banana { 
    float bendAmt; 

    AdvancedBanana(float length, float bendAmt) { 
     this->length = length; this->bendAmt = bendAmt; 
    } 
}; 


int main() 
{ 
    Banana b = CreateByHalfLength(1); 
    AdvancedBanana bb(1, 2); 
    //bb.CreateByHalfLength(2); 

    return 0; 
} 
1

如果你想自動限制派生類重載static Banana CreateByHalfLength(float halfLength);然後一個非常快速的方式用於封裝virtual final方法內部的功能。

例如

struct Banana { 
    ... 
    // Create a namesake wrapper for the `static` function and make it final 
    virtual 
    Banana CreateByHalfLength(float halfLength) final { 
    return CreateByHalfLengthImpl(halfLength); 
    } 

    static Banana CreateByHalfLengthImpl(float halfLength) { 
    return Banana(halfLength * 2); 
    } 
}; 

利用這種佈置,現在任何派生類將不能夠創建一個類似的功能static或非static
Here is a demo

該方法的缺點是您添加的功能開銷爲virtual以及使用未使用的對象調用。

相關問題