If you can give the class enough useful functionality to justify the added complexity of not being a string, then do it. For identifiers like ISBN and ISIN, I suspect this is not the case.
For an identifier class to be useful, I'd expect it to look something like this:
class ISIN {
fromCUSIP()
fromRawISINString()
toString(ISIN::FormatType)
getExchange()
getCountryCode()
getLastFourDigits()
getWhateverCode()
...
}
If instead it looks more like this:
class ISIN {
getString()
setString()
}
Then I'd ditch the class entirely, use regular strings everywhere, and make sure I consistently use "isin" in all the relevant variable names.
Note that in some languages, adding a new type has almost no "added complexity" in typical programs, in which case you'd be encouraged to create the new type even if it had no functionality at all. But this is not the case for most traditional OOP languages like C++.