引用

时间:2017-11-21 18:46:28

标签: c++ reference decorator virtual-functions

以下代码尝试使用引用实现基本的Decorator设计模式,以引用基本组件类Paragraph

#include <string>
#include <iostream>

using std::cout; using std::endl; using std::string;

// component
class Paragraph{
public:
   Paragraph(const string& text = "") : text_(text) {}
   virtual string getHTML() const { return text_; }
private:
   const string text_;
};

// first decorator
class BoldParagraph : public Paragraph {
public:
   BoldParagraph(const Paragraph& wrapped): wrapped_(wrapped) {}
   string getHTML() const override {
      return "<b>" + wrapped_.getHTML() + "</b>";
   }
private:
   const Paragraph &wrapped_;
};


// second decorator
class ItalicParagraph : public Paragraph {
public:
   ItalicParagraph(const Paragraph& wrapped): wrapped_(wrapped) {}
   string getHTML() const override {
      return "<i>" + wrapped_.getHTML() + "</i>";
   }
private:
   const Paragraph &wrapped_;
};

int main(){
   Paragraph p("Hello, World!");

   BoldParagraph     bp(p); cout <<  bp.getHTML() << endl;
   BoldParagraph   bbp(bp); cout << bbp.getHTML() << endl; 
   ItalicParagraph ibp(bp); cout << ibp.getHTML() << endl;
}

运行时会生成

<b>Hello, World!</b>
<b>Hello, World!</b>
<i><b>Hello, World!</b></i>

而不是

<b>Hello, World!</b>
<b><b>Hello, World!</b></b>
<i><b>Hello, World!</b></i>

也就是说,如果第二个包装函数getHML()用于对象BoldParagraph的相同子类bbp,则它似乎被跳过,但如果它用于不同的子类{{1}则不会被跳过对象ItalicParagraphBoldParagraph。使用指针而不是引用的类似代码按预期工作。

为什么会这样?

3 个答案:

答案 0 :(得分:1)

正在调用默认的复制构造函数。这将创建传入(bp)的原始对象的副本,而不是bp周围的包装。您可以通过声明自己的复制构造函数来修复,但我不推荐它:

WITH [0,1,5,7,9,11] as list
UNWIND list as x
WITH CASE WHEN x = 0 THEN -1 ELSE  (x / 5) * 5 END as results
return results

为了澄清,默认的复制构造函数复制了在object中传递的值,如下所示:

  BoldParagraph(const BoldParagraph &wrapped) : wrapped_(wrapped) {}

而且,我越是想到它,我认为我的建议修复越多越不正确。可能/可能会有令人讨厌的副作用。我建议通过让你的构造函数指针来修复。

这里的答案将显示具有不执行副本的复制构造函数的可能副作用: Copy Constructor in C++ is called when object is returned from a function?

使用包装而不是副本的复制构造函数的具体示例:

BoldParagraph(const BoldParagraph &original) : wrapped_(original.wrapped_) {}

输出:

void AFunction(BoldParagraph bp)
{
  cout << bp.getHTML() << endl;
}
int main() {
  Paragraph p("Hello, World!");

  BoldParagraph     bp(p); cout << bp.getHTML() << endl;
  BoldParagraph   bbp(bp); cout << bbp.getHTML() << endl;
  AFunction(bbp); 

答案 1 :(得分:1)

原因是bbp(bp) bp类型BoldParagraph调用(隐式定义的)复制构造函数BoldParagraph::BoldParagraph(const BoldParagraph &)然后执行成员明智的复制/赋值,例如wrapper_被切片,然后是Paragraph &类型,而不是BoldParagraph &。要解决这个问题,您必须为BoldParagraph::BoldParagraph(const BoldParagraph &)提供一个明确的复制构造函数,然后调用您的个人:

 BoldParagraph(const BoldParagraph& wrapped) : BoldParagraph((Paragraph&)wrapped) {} ;

答案 2 :(得分:0)

哦,太棒了,非常感谢!这很难被发现。我最后添加了这个

 BoldParagraph(const BoldParagraph& wrapped) : 
         BoldParagraph(static_cast<const Paragraph&>(wrapped)) {}

让代码开心