Finally came back to this problem (testers wouldn't stop bugging me about it).
Found a potential solution!
QQmlProperty::write(QObject*, const QString& name)
It doesn't seem to be documented, but calling this function seems to break any existing QML bindings on the specified property. So I just create a separate WRITE function for my aliased property:
Q_PROPERTY(int number READ GetNumber WRITE SetNumber NOTIFY NumberChanged)
Q_PROPERTY(int numeral READ GetNumber WRITE OverwriteNumber NOTIFY NumberChanged)
void OverwriteNumber(const int value)
{
QQmlProperty p(this, "number");
p.write(value);
}
Seems to work for me.
Basically gets around the problem of C++ being unaware of the binding by writing to the property through the QML context, I guess. It's probably much slower than calling the setter directly, so probably not ideal for properties that change frequently, but it will suffice for my purposes.