簡體   English   中英

shared_ptr和私有繼承

[英]shared_ptr and private inheritance

這是一個玩具示例,說明了我遇到的問題。 該應用程序相當無關緊要(它本質上是一個鏈接的元素列表,最后有一個特殊的行為)。 我無法使用派生指針構造基類shared_ptr,並且由於某種原因鏈接到我正在使用私有繼承的事實。

#include <iostream>
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>

using namespace std;

// An Item in a linked list
class A
{
public:
  //friend class B;
  typedef boost::shared_ptr<A> APtr;
  A() : next_() {}
  A(APtr n) : next_(n) {}
  APtr next() { return next_; }
  void setNext(APtr n) { next_ = n; }

  virtual void doIt() { /* standard behavior */ }  

private:
  APtr next_;
};


class B : private A // B really is a special A
                    // that should have different behavior
                    // at the tail of the chain
                    // but I want to hide A's interface
                    // to external clients
{
public:
  typedef boost::shared_ptr<B> BPtr;
  B(A::APtr prev) 
  { // Set this object as the tail
    prev->setNext(APtr(this));  /* WHY CAN'T I CONSTRUCT APtr(this) 
                                   WITH PRIVATE INH. */
  }
  void doIt() {/*special behavior at end */}

};

int main()
{
  A::APtr dummyPtr;
  A::APtr head = boost::make_shared<A>(dummyPtr);
  B::BPtr tail = boost::make_shared<B>(head);

  for(A::APtr curr = head; curr; curr=curr->next()){
    curr->doIt();
  }

  return 0;
}

我明白了

/usr/include/boost/smart_ptr/shared_ptr.hpp: In constructor ‘boost::shared_ptr<T>::shared_ptr(Y*) [with Y = B, T = A]’:
derived_shared.cpp:31:   instantiated from here
/usr/include/boost/smart_ptr/shared_ptr.hpp:352: error: ‘A’ is an inaccessible base of ‘B’

我的印象是私有繼承允許Derived類仍然訪問基類的公共接口,但將該接口隱藏到外部客戶端。 為什么私有繼承會導致此錯誤(如果我公開繼承,它會起作用)?

改變這一行:

prev->setNext(APtr(this)); 

prev->setNext(APtr(static_cast<A*>(this))); 

它編譯。

或者至少在使用std庫時std 它通常類似於boost

還有其他錯誤,但是將B*A*

為什么這樣做? 因為構造函數std::shared_ptr<A>的模板不是你想象的那樣! 它更像是template <class X> std::shared_ptr(X* v) 因此,實際的B*A*演員被推遲並且在非朋友成員中失敗。

但是如果你將B*指針(即this )轉換為class B方法中的A* (唯一沒有friend聲明合法的地方),你就進入了。

注意:私人繼承原則上沒有任何錯誤。 它不是反模式,並且有充分理由提供。 考慮組合,但禁止應用程序的某些部分“訪問”其“真實”類型的對象有很多用途。 例如,傳遞一個對象A,它有一些只有對象工廠可以訪問的B螺栓。

PS:構造函數是template<class T> shared_ptr<T* v>shared_ptr使用傳遞給它的類型的刪除器。 因為你並不懷疑share_ptr巧妙地調用'正確'的析構函數,即使它不是虛擬的。 我的“修復”實際上顛覆了這種聰明所以要小心在右側缺失者或(推薦)作出的析構函數傳遞A虛擬的。

PPS:

最后一個完整的工作程序(使用STL。抱歉,我沒有Boost):

#include <iostream>
#include <memory>

// An Item in a linked list
class A
{
public:
  //friend class B;
  typedef std::shared_ptr<A> APtr;
  A() : next_() {}
  A(APtr n) : next_(n) {}
  APtr next() { return next_; }
  void setNext(APtr n) { next_ = n;}

  virtual void doIt() { std::cout<<"normal thing"<<std::endl; }  

  virtual ~A(){}
private:
  APtr next_;
};

class B : public std::enable_shared_from_this<A>, private A // B really is a special A
                    // that should have different behavior
                    // at the tail of the chain
                    // but I want to hide A's interface
                    // to external clients
{
public:
  template<class X> friend class std::enable_shared_from_this;

  typedef std::shared_ptr<B> BPtr;


  static BPtr makeit(A::APtr prev){
    BPtr B(std::make_shared<B>());
    prev->setNext(B->shared_from_this());
    return B;
  } 

  void doIt() {std::cout<<"end thing"<<std::endl;}
private: 
  B(){}
};

int main()
{
  A::APtr dummyPtr;
  A::APtr head = std::make_shared<A>(dummyPtr);
  B::BPtr tail = B::makeit(head);

  for(A::APtr curr = head; curr; curr=curr->next()){
    curr->doIt();
  }

  return 0;
}

您需要使用enable_shared_from_this ,否則您將嘗試創建shared_ptr兩個“系列”,這將無效。

我已經制作了一個工廠方法,因為修復構造函數不起作用! enable_shared_from_this的前提是enable_shared_from_this存在std::shared_ptr ,我想這意味着'完全構造'。

以下構造函數對我不起作用:

B(A::APtr prev){
   prev->setNext(shared_from_this());
} 

也就是說,如果你繼承了enable_shared_from_this那么將所有構造函數設為私有並提供返回shared_ptr工廠是個好主意。 否則,如果調用代碼本身不能確保“預先存在的shared_ptr ”條件,則可能會遇到麻煩。 一個令人討厭的耦合,如果有的話。

當你使用私有繼承時,你基本上說“我希望B用A來實現,但我不希望它像A(is-a A)一樣使用”

在這里,你給boost::shared_ptr一個指向B的指針,好像它是A.

這與你的設計相矛盾。 也許聲明boost::shared_ptr<A> B的朋友會有所幫助,但它仍然是一個奇怪的設計。

附加說明:如果您希望B是一個不暴露A接口的特殊A,請考慮組合而不是私有繼承

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM