The solution is to use const
.
Say you have a class MusicalSheet
. You can define getters and setters for whatever data you want. Make the setters const
so you can't call them on a const
object or reference.
class MusicalSheet
{
public:
void setNote(size_t position, Note note);
const Note& getNote(size_t position) const;
private:
// Data members
};
Then you have your parsing logic and business logic, and main
to tie them together:
void parseMusic(MusicalSheet &sheet, Input &input);
void businessLogic(const MusicalSheet &sheet);
int main()
{
MusicalSheet sheet;
Input input(...);
parseMusic(sheet, input);
businessLogic(sheet);
}
Your parsing function has a non const reference to the object, so it can call setNote
to fill in the data. The business logic can only access getNote
as it's marked const
. And getNote
returns a const
reference, so the inner object is also not modifiable by the business logic.
The example MusicalSheet
class is obviously over simplified, and can in fact be replaced with just a std::vector<Note>
, using operator[]
to get and set the individual notes (along with many other functions). Like MusicalSheet
, with a const
vector you can only access the inner objects, not modify them.
Read the documentation on the const type qualifier and const-qualified member functions
One caveat with const
is pointers. Making an int*
const will give you a int* const
, which is a constant pointer to a non-constant int. This is also true for smart pointers.
To get around it you can do something like this:
class DataHolder
{
public:
std::unique_ptr<Data>& getData() { return _data; }
const Data* getData() const { return _data.get(); }
private:
std::unique_ptr<Data> _data;
};
Now with a DataHolder
you can reassign the pointer (e.g. dataHolder.getData() = std::make_unique<Data>(...);
), but with a const DataHolder
all you can do is access a const Data*
.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…