2

I want to write a c++1z program based on Java code

First an interface is declared in Java.

public interface MyExpression {
  public boolean interpret();
}

An abstract class in java that implements the interface

public abstract class NonTerminal implements MyExpression {
  protected MyExpression left, right;
  public void setLeft(MyExpression left) {
    this.left = left;
  }
  public void setRight(MyExpression right) {
    this.right = right;
  }
}

and finally the class

public class Or extends NonTerminal {
  public boolean interpret() {
    return left.interpret() || right.interpret();
  }
  public String toString() {
    return String.format("(%s | %s)", left, right);
  }
}

How do I create this functionality in modern c++?

update c++ snippet

#include <iostream>
#include <memory>
#include <ostream>

class BooleanExpression {
public:
    virtual ~BooleanExpression() = default;
    virtual bool interpret() = 0;
};

class NonTerminal : public BooleanExpression {
protected:
    std::unique_ptr<BooleanExpression> left, right;

public:
    void setLeft(std::unique_ptr<BooleanExpression>&& left) {
        this->left = std::move(left);
    }

    void setRight(std::unique_ptr<BooleanExpression>&& right) {
        this->right = std::move(right);
    }
};

class Terminal : public BooleanExpression {
protected:
    bool value;

public:
    Terminal(bool value) : value(value) {}

    //tostring
};

class False : public Terminal {

public:
    False() : Terminal(false) {}

    //tostring
};

class True : public Terminal {

public:
    True() : Terminal(true) {}

    //tostring
};

class Or : public NonTerminal {
public:
    bool interpret() {
        return left->interpret() || right->interpret();
    }
};

class And : public NonTerminal {
public:
    bool interpret() {
        return left->interpret() && right->interpret();
    }

    //tostring
};

int main() {

    using namespace std;
    auto  t1 = make_unique<True>();
    auto f1 = make_unique<False>();

    auto or1 = make_unique<Or>();
    or1->setLeft(t1);


    return 0;
}

This code does not compile. or1->setLeft does not accept t1, ie make_unique().

Captain Nemo
  • 345
  • 2
  • 14

2 Answers2

3

MyExpression is an abstract class, and cannot be instanciated, you need to pass around pointers, instead of values.

I suggest you use std::unique_ptr, as it will take care of calling delete for you.

Your NonTerminal class would look like this.

class NonTerminal  {
protected:
    std::unique_ptr<MyExpression> left, right;

public:
    void setLeft(std::unique_ptr<MyExpression>&& left) {
        this.left = std::move(left);
    }

    void setRight(std::unique_tr<MyExpression>&& right) {
        this.right = std::move(right);
    }
};

As a side note, you need to add to NonTerminal class declaration that your destructor is virtual, otherwise your code will invoke undefined behavior.

class MyExpression {
public: 
virtual ~MyExpression() = default;
virtual bool interpret() = 0;
};
Kaldrr
  • 2,780
  • 8
  • 11
2

You are getting confused by deference of value semantics between Java and C++. void setRight(MyExpression right) in Java accepts a reference to MyExpression while void setRight(MyExpression right) in C++ accepts a value of (abstract) type. References in C++ can be passed only explicitly like this: void setRight(MyExpression & right). Rebinding references in C++ is not supported and this.left = left; actually performs copy assignment of value. If you want to rebind a reference then you should use std::reference_wrapper or boost::optional reference. There is also no garbage collection in C++ that will prolong lifetime of objects until they are not needed anymore so you should manually manage lifetime of all the objects and ensure that they survive long enough for references to remain valid.

user7860670
  • 35,849
  • 4
  • 58
  • 84
  • trying to figure out what you mean by reference_wrapper. Maybe it is related with my problem in my updated question. – Captain Nemo Aug 29 '19 at 11:40
  • @CaptainNemo [`std::reference_wrapper`](https://en.cppreference.com/w/cpp/utility/functional/reference_wrapper), `setLeft` requires an argument to be an rvalue. Though using `std::unique_ptr` (or `std::shared_ptr`) everywhere is not a good idea unless transferring or sharing ownership is your goal. – user7860670 Aug 29 '19 at 11:43
  • I cannot understand why my new cpp code does not compile. I updated my question – Captain Nemo Aug 29 '19 at 12:09
  • 1
    @CaptainNemo You should get familiar with [value semantics in C++](https://stackoverflow.com/questions/3106110/what-is-move-semantics/3109981) first, java experience won't be helpful in this matter at all. – user7860670 Aug 29 '19 at 12:46