首页 \ 问答 \ 复合模式的递归迭代器(Recursive iterator for composite pattern)

复合模式的递归迭代器(Recursive iterator for composite pattern)

我有树类AbstractComponent,Leaf和Composite:

public abstract class AbstractComponent {
    privavte String name;

    [...]
}

public class Leaf extends AbstractComponent {
    [...]
}

public Composite extends AbstractComponent {
    private List<AbstractComponent> children;

    public void addChild(AbstractComponent a) {
        [...] 
    }

    public List<AbstractComponent> getChildren() {
        return children;
    }
}

我的问题:如何在Java中为基于组合模式的模型编写递归迭代器? 我读过这个问题( 创建一个递归迭代器 )。 可以采用我的问题的公认答案? 我还发现了Guava的TreeTraverser类,但它似乎只限于一个表示节点的类。


I have the tree classes AbstractComponent, Leaf and Composite:

public abstract class AbstractComponent {
    privavte String name;

    [...]
}

public class Leaf extends AbstractComponent {
    [...]
}

public Composite extends AbstractComponent {
    private List<AbstractComponent> children;

    public void addChild(AbstractComponent a) {
        [...] 
    }

    public List<AbstractComponent> getChildren() {
        return children;
    }
}

My question: How can I write a recursive iterator in Java for a model that is based on the composite pattern? I read this question (Creating a recursive iterator). It is possible to adopt the accepted answer to my problem? I also found the TreeTraverser class from Guava but it seems to be limited to one class that represents a node.


原文:https://stackoverflow.com/questions/30779515
更新时间:2023-08-07 06:08

最满意答案

    Ding * neu = new Ding(tmp);
    return *neu;

这是错的。 您正在动态分配一个Ding ,然后强制它的副本。 因为Ding是动态分配的,所以你正在泄漏它,它的生命周期超出了return语句,并且编译器无法从它移动 。 请注意,您没有返回临时。

改为:

    return Ding(tmp);

甚至:

    return tmp;

由于构造函数采用const char*明确 ,编译器将使用它来创建一个新的Ding对象。 在这两种情况下,临时的生命周期都不会超出return语句,编译器也会移动

(这个答案假设您了解从返回的对象到d3的副本已经被删除,如果这是您期望移动的位置,那么编译器做了更好的事情:完全避免操作)。

编辑由于DeadMG编写了一个规范形式,但它包含错误我会跟进:

关于运算符重载有很多话要说,但是一个共同的建议(我给出和遵循的那个)是将operatorX=作为一个成员函数实现(它是一个应用于左侧的操作)然后将operator+作为一个自由函数实现就前者而言。 在C ++ 11中,它将是:

class X {
   X& operator+=( X const & ); // we do not modify the rhs internally
};
X operator+( X lhs, X const & rhs ) {
  lhs += rhs;                  // reuse implementation
  return lhs;
}

需要注意的一些事项: operator+在类型方面是对称的,因为它是一个自由函数。 所有在右侧都可能发生的隐式转换也可以在lhs中找到。 在您的特定情况下, Ding可以从const char*隐式转换,这意味着通过拥有一个自由函数operator+您可以编写:

Ding d( "A" );
const char* str = "B";
d + d;     // no conversions
d + str;   // conversion on the right hand side
str + d;   // conversion on the left hand side

通过将operator+=定义为公共成员函数,您需要编写单个实现,并且该实现可以重用,因此您可以获得两个运算符,其中一个(以及三个额外的代码行是微不足道的)。

按值计算的参数和按值返回。 如果参数是临时的,这使编译器可以将副本删除为参数。 由于存在移动构造函数 ,因此也不会有任何内部副本,参数将被修改移动到返回对象。 (不能省略第二份副本)。

我前段时间在运算符重载上写了不止这些......它没有明确处理优化( 移动 ),但还有其他帖子处理它的C ++ 03版本。 从那个到C ++ 11功能,你应该能够填补空白。


    Ding * neu = new Ding(tmp);
    return *neu;

This is wrong. You are dynamically allocating a Ding and then forcing a copy of it. Because the Ding is dynamically allocated, you are leaking it, it's lifetime extends beyond the return statement and the compiler cannot move from it. Note that you are not returning a temporary.

Change that to:

    return Ding(tmp);

Or even:

    return tmp;

As your constructor taking a const char* is not explicit, the compiler will use it to create a new Ding object. In both cases, the lifetime of the temporary does not extend beyond the return statement and the compiler will move.

(This answer assumes that you understand that the copy from the returned object to the d3 has been elided, if that is where you expected the move, then the compiler did something better: avoid the operation altogether).

EDIT As DeadMG has written a canonical form but it includes errors I will follow up on that:

There is much to say about operator overloading, but a common recommendation (the one I give and follow) is to implement operatorX= as a member function (it is an operation applied to the left hand side) and then implement operator+ as a free function in terms of the former. In C++11 that would be:

class X {
   X& operator+=( X const & ); // we do not modify the rhs internally
};
X operator+( X lhs, X const & rhs ) {
  lhs += rhs;                  // reuse implementation
  return lhs;
}

Some things to note: operator+ is symmetric with respect to types as it is a free function. All implicit conversions that can happen on the right hand side are also available in the lhs. In your particular case, Ding is implicitly convertible from const char*, which means that by having a free function operator+ you can write:

Ding d( "A" );
const char* str = "B";
d + d;     // no conversions
d + str;   // conversion on the right hand side
str + d;   // conversion on the left hand side

By defining operator+= as a public member function you need to write a single implementation and that implementation can be reused, so you get two operators for the cost of one (and three extra lines of code that are trivial).

Argument by value and return by value. This enables the compiler to elide the copy to the parameter if the argument is a temporary. As there is a move constructor, there will not be any internal copy either, the argument will be modified and moved to the return object. (This second copy cannot be elided).

I wrote a bit more than this on operator overloading here some time ago... It does not explicitly deal with optimizations (moving) but there are other posts there that deal with the C++03 version of it. From that to C++11 features you should be able to fill in the blanks.

相关问答

更多
  • 这是一个演员的语法。 这是因为cast和一元加法,减法和乘法(解引用运算符)比它们的二进制对象具有更高的优先级。 由于这里的空白并不重要,因此也可以这样读取: A a = (A()) +A(); cast和unary+比二元operator+ unary+有更高的优先级,所以表达式取前者的含义。 你可能想知道(和我一样),当内部的东西不是一个类型的时候,你可以如何投射。 请输入最具威胁性的内容! ,这意味着我试图将一个类型为+A()的对象转换为一个带有0个参数的函数并返回一个类型为A的对象。 为了 ...
  • 它只是“构造函数”的缩写 - 这也是IL中调用的构造函数。 例如,打开反射器并查看一个类型,您将看到各种构造函数的名为.ctor成员。 It's just shorthand for "constructor" - and it's what the constructor is called in IL, too. For example, open up Reflector and look at a type and you'll see members called .ctor for the va ...
  • 错误是正确的; 移动构造函数只在类没有用户定义的析构函数时隐式生成。 如果你添加一个析构函数,那么你将禁止默认的移动构造函数,并尝试复制构造函数。 当一个类具有不可复制的基类时,默认的复制构造函数的生成会被抑制,因为Derived既不可复制也不可移动。 解决方案只是将一个移动构造函数添加到Derived 。 The error is correct; move constructors are only implicitly generated when the class has no user-defi ...
  • 我稍微修改了你的主程序,以更好地理解输出: int main() { std::cout << "default\n"; Map m; std::cout << "\ncopy\n"; Map m1(m); std::cout << "\nmove\n"; Map m2(Map(m1)); std::cout << "\nmove\n"; Map m3(createMap()); } 这是g++ -fno-elide-construct ...
  • 使用lambda表达式。 int main() { test t; std::function f = [=](){ foo(t); }; f(); return 0; } 由于使用lambda的难以置信的容易性,绑定非常多余。 此外,您在发布模式下进行了所有优化的编译,对吧? 您不会只获得一个复制构造函数调用,因为首先必须生成一个函数对象,然后将该函数对象分配给std :: function。 也许它可能是std::move ? 由于你没有lambdas甚至 ...
  • 所以我的问题是,标准保证的第一个报价(包括“或” )? 是的,您的第一个报价由标准保证。 引用标准(草案n3690): 12.8复制和移动类对象[class.copy] 7 /如果类定义没有显式声明复制构造函数,则会隐式声明一个。 如果类定义声明了移动构造函数或移动赋值运算符,则隐式声明的复制构造函数被定义为已删除; 否则,它被定义为默认值(8.4)。 如果类具有用户声明的复制赋值运算符或用户声明的析构函数,则不推荐使用后一种情况。 So my question is, is the first quote ...
  • 明确允许编译器忽略临时对象的复制(或移动)。 基本上,对象是在期望有效结果的地方构建的。 如果构造函数或析构函数具有副作用,则甚至允许使用此省略。 相关条款是12.8 [class.copy]第31段: 当满足某些条件时,允许实现省略类对象的复制/移动构造,即使为复制/移动操作选择的构造函数和/或对象的析构函数具有副作用。 在这种情况下,实现将省略的复制/移动操作的源和目标视为仅仅两种不同的引用同一对象的方式,并且该对象的破坏发生在两个对象的后期时间。没有优化就被破坏了。 复制/移动操作的省略,称为复制省略 ...
  • Ding * neu = new Ding(tmp); return *neu; 这是错的。 您正在动态分配一个Ding ,然后强制它的副本。 因为Ding是动态分配的,所以你正在泄漏它,它的生命周期超出了return语句,并且编译器无法从它移动 。 请注意,您没有返回临时。 改为: return Ding(tmp); 甚至: return tmp; 由于构造函数采用const char*不明确 ,编译器将使用它来创建一个新的Ding对象。 在这两种情况下,临时的生命周期都不会 ...
  • X make_x() // build an X with some data { X myNewObject; // Constructor1 gets called here // fill data.. return myNewObject; // Constructor3 gets called here } myNewObject在这个函数范围的末尾被销毁,所以编译器可以通过移动来消除它的内容。 X make_x() // build an X with some dat ...
  • 通常情况下, EscapedString es2 = es; 将调用复制构造函数,但是您明确告诉它不要通过使复制构造函数explicit : explicit EscapedString(const EscapedString &strEscaped) 标记为explicit的构造函数永远不能通过自动类型转换来调用。 它只能被明确地调用,你在这里做了: EscapedString es(EscapedString("Abc?def")); 这是编译器遇到EscapedString es2 = es;时会 ...

相关文章

更多

最新问答

更多
  • 获取MVC 4使用的DisplayMode后缀(Get the DisplayMode Suffix being used by MVC 4)
  • 如何通过引用返回对象?(How is returning an object by reference possible?)
  • 矩阵如何存储在内存中?(How are matrices stored in memory?)
  • 每个请求的Java新会话?(Java New Session For Each Request?)
  • css:浮动div中重叠的标题h1(css: overlapping headlines h1 in floated divs)
  • 无论图像如何,Caffe预测同一类(Caffe predicts same class regardless of image)
  • xcode语法颜色编码解释?(xcode syntax color coding explained?)
  • 在Access 2010 Runtime中使用Office 2000校对工具(Use Office 2000 proofing tools in Access 2010 Runtime)
  • 从单独的Web主机将图像传输到服务器上(Getting images onto server from separate web host)
  • 从旧版本复制文件并保留它们(旧/新版本)(Copy a file from old revision and keep both of them (old / new revision))
  • 西安哪有PLC可控制编程的培训
  • 在Entity Framework中选择基类(Select base class in Entity Framework)
  • 在Android中出现错误“数据集和渲染器应该不为null,并且应该具有相同数量的系列”(Error “Dataset and renderer should be not null and should have the same number of series” in Android)
  • 电脑二级VF有什么用
  • Datamapper Ruby如何添加Hook方法(Datamapper Ruby How to add Hook Method)
  • 金华英语角.
  • 手机软件如何制作
  • 用于Android webview中图像保存的上下文菜单(Context Menu for Image Saving in an Android webview)
  • 注意:未定义的偏移量:PHP(Notice: Undefined offset: PHP)
  • 如何读R中的大数据集[复制](How to read large dataset in R [duplicate])
  • Unity 5 Heighmap与地形宽度/地形长度的分辨率关系?(Unity 5 Heighmap Resolution relationship to terrain width / terrain length?)
  • 如何通知PipedOutputStream线程写入最后一个字节的PipedInputStream线程?(How to notify PipedInputStream thread that PipedOutputStream thread has written last byte?)
  • python的访问器方法有哪些
  • DeviceNetworkInformation:哪个是哪个?(DeviceNetworkInformation: Which is which?)
  • 在Ruby中对组合进行排序(Sorting a combination in Ruby)
  • 网站开发的流程?
  • 使用Zend Framework 2中的JOIN sql检索数据(Retrieve data using JOIN sql in Zend Framework 2)
  • 条带格式类型格式模式编号无法正常工作(Stripes format type format pattern number not working properly)
  • 透明度错误IE11(Transparency bug IE11)
  • linux的基本操作命令。。。