2016-07-15 46 views
2

考慮一個用例:是否可以阻止引用的上傳?

  • 你已經有了一個可複製類Base,對於你真的不關心會發生什麼吧。
  • 從此公開繼承是Derived類,該類不應轉換爲Base。一點也不。甚至沒有提及它,參考Base,換句話說,隱式地綁定應該是非法的:Derived& -> Base&

注:Derived類可以是可複製,只是它的內部永遠也不會被放入一個普通Base對象。由於可以直接禁止從Derived開始禁止Base的初始化,所以如果編譯可以被禁止繞過它,問題仍然存在:Derived& -> Base& -> Base

假設static_cast,指針不是一個問題 - 只在函數調用中自動綁定。

下面是該問題的一個基本的例子:

#include <iostream> 
using namespace std; 

class Derived; 

class Base 
{ 
public: 
    Base(int var) 
     : m_var(var) 
    { 
     std::cout << "Base default ctor with value: " << m_var << std::endl; 
    } 

    Base& operator=(const Derived&) = delete; 
    Base& operator=(Derived&&) = delete; 
    Base(const Derived&) = delete; 
    Base(Derived&&) = delete; 

    int m_var; 
}; 

class Derived : public Base 
{ 
public: 
    Derived(int var) 
     : Base(var) 
    { 
     std::cout << "Derived default ctor with value: " << m_var << std::endl; 
    } 

    Base unprotect() const 
    { 
     std::cout << "Derived unprotected with value: " << m_var << std::endl; 
     return Base(m_var); 
    } 
}; 

void foo(Base& base) 
{ 
    std::cout << "foo with value: " << base.m_var << std::endl; 
    // Base b2 = base; // just copied Derived, goal is to prohibit it! 
} 

int main() 
{ 
    Base b1(1); 
    foo(b1); 

    Derived d1(2); 
    foo(d1);   // is it at all possible to disallow implicit Derived& -> Base&? 
    // rationale is to require explicit: Base& Dervied::getBaseRef()  

    // Base b2 = d1; // illegal: error: use of deleted function 'Base::Base(const Derived&)' 

    return 0; 
} 
+2

_「從它公開繼承是Derived類,它不應該轉換爲Base。」_爲什麼它繼承'Base'呢?這聽起來很奇怪。 –

+1

它似乎更像是一個設計問題而不是代碼問題。 –

+0

@πάνταῥεῖ由於基於'Base' *的不幸的大型代碼*基礎,其中明確的轉換仍將被使用,但是您可以更輕鬆地保留它們的軌跡*。 – hauron

回答

3

從它公開繼承是Derived類,它不應該轉換爲Base。一點也不。

從OOP設計的角度來看,這兩件事情非常矛盾。我認爲在語言中沒有辦法阻止將派生對象作爲公共基礎(通過引用的隱式轉換方式)。

您可以非公開地繼承Base

這也會阻止顯式投射 - 您仍然希望能夠做到這一點。但僅限於課堂範圍之外。您可以改爲提供一個成員可以訪問的基本實例:

class Derived : Base 
{ 
public: 
    // ... 
    Base& base() { 
     return *this; 
    } 
}; 

現在,你可以替換呼叫的那些顯式強制Derived::base,而隱式轉換不保持被允許。

Derived d; 
Base& b = d;  // (implicit) conversion fails 
Base& b = d.base(); // this works 

您可能還想實現const版本的函數。我將把它作爲一個練習。

1

既然你是不是繼承來代替(你直接說你不想派生永遠看作爲一個基地),我假設你繼承了一個實現。在這種情況下,答案很明確:根據您的確切需要繼承private或可能protected。這完全禁止所有這樣的基類轉換,同時仍然允許你的孩子訪問基類的實現。

如果您需要公開暴露一個或兩個基本成員,您可以隨時將它們using導入派生類。

3

我的標準方法是使用私有繼承,然後用using解除所有想要的方法,構造函數和運算符。

class Derived : private Base { 
    public : 
    using Base::Base; 
    using Base::some_base_method; 
} 

int main(){ 
    Derived d1(2); 
    d1.some_base_method(); 
} 

對於壞的和更糟的是,這也使得很多未來的基礎無法通過Derived的公共接口添加到Base中。 它也適用於模板,包括CRTP。

相關問題