Reputation: 683
I'm writing a toy regular expression engine in C++ as a learning exercise and I'm running into a compiler error. Here's the definition for the classes that implement the different expression subtypes:
// ***************************************************************
// ***************************************************************
class RegexExpression {
public:
virtual RegexResult match(std::string);
};
// ***************************************************************
class RegexTerm : public virtual RegexExpression {
public:
RegexTerm(char c) : _matchChar(c) {}
RegexResult match(std::string);
private:
char _matchChar;
};
// ***************************************************************
class RegexNil : public virtual RegexExpression {
public:
RegexResult match(std::string);
};
// ***************************************************************
// ***************************************************************
class RegexBinaryExpression : public virtual RegexExpression {
public:
RegexBinaryExpression
(RegexExpression &lhs, RegexExpression &rhs) :
_lhs(lhs), _rhs(rhs) {}
protected:
RegexExpression _lhs;
RegexExpression _rhs;
};
// ***************************************************************
class RegexOr : public RegexBinaryExpression {
public:
RegexResult match(std::string);
};
// ***************************************************************
class RegexAnd : public RegexBinaryExpression {
public:
RegexResult match(std::string);
};
However when I try to instantiate RegexOr, for example:
RegexOr regex(RegexTerm('a'), RegexNil());
Then I get a compiler error telling me that the 2 argument constructor from RegexBinaryExpression isn't visible.
If I explicitly define the constructor in RegexOr, for example:
RegexOr(RegexExpression &l, RegexExpression &r) : RegexBinaryExpression(l, r) {}
Then I'm told that RegexNil cannot be converted to RegexExpression.
What am I doing wrong here?
Upvotes: 1
Views: 290
Reputation: 21763
You cannot pass a temporary object to a non-const reference parameter. To make it compile, you will need to change the parameter to const reference (or by value).
You have a bigger problem though. When you copy the parameters to RegexBinaryExpression's members, they are stored as RegexExpression objects and not as derived objects. The information about the derived type is lost. This is called object slicing.
You will need to allocate the regex objects dynamically and store pointers to them in your classes. I would recommend smart pointers. You could also make the type of regex objects stored in the class, template parameters, instead of an inheritance hierarchy. That is probably harder to implement and has some drawbacks.
Upvotes: 2
Reputation: 96233
At least prior to C++11 you definitely have to implement the constructor yourself in RegexOr
. However you're implementing it as taking a non-const reference parameter which you then attempt to bind from a temporary, which is forbidden by the language.
Instead take the parameter by const reference (or possibly even by value):
RegexBinaryExpression(const RegexExpression &lhs, const RegexExpression &rhs)
: _lhs(lhs)
, _rhs(rhs)
{}
RegexOr(const RegexExpression &l, const RegexExpression &r) : RegexBinaryExpression(l, r) {}
Upvotes: 2