Board index » cppbuilder » read-only class member variable

read-only class member variable


2005-06-04 04:16:58 AM
cppbuilder30
I have a class member variable. I like it can be read directly but can be writen only by call member function. Is there any way
to do that? (I don't want to make it as a private variable
since there are too many changes to current codes if do so.)
Thanks.
didan
 
 

Re:read-only class member variable

"didan" < XXXX@XXXXX.COM >writes:
Quote
I have a class member variable. I like it can be read directly but
can be writen only by call member function. Is there any way to do
that? (I don't want to make it as a private variable since there are
too many changes to current codes if do so.) Thanks. didan
If it's const, it can't be changed by anyone. If it's non-const, then
it can be modified by anyone who can access it. If it's public, it
can be accessed by anyone.
Thus, non-const public data is inherently writeable by anyone.
You may use a trick, however, that does involve private data. Suppose
your public data is called "pubdata", you can do this:
class Foo
{
public:
Foo();
int const & pubdata;
void set_data(int x);
private:
int data;
};
Foo::Foo() : pubdata(data), data(0)
{ }
void Foo::set_data(int x) { data = x; }
int main()
{
Foo f;
int val = f.pubdata; // OK
f.set_data(999); // OK
f.pubdata = 123; // ERROR
}
Member functions can modify data, and it's private, so other code
cannot access it. However, publically, you have pubdata, which is a
reference to a const int, and it refers to data. Thus, when accessing
the data through pubdata, it's in a const context, but when accessing
it through data, it's private and writeable--which matches your
requirements: only writeable by members, readable by everyone publically.
Will this work for you?
--
Chris (TeamB);
 

Re:read-only class member variable

"didan" < XXXX@XXXXX.COM >wrote in message
Quote
I have a class member variable. I like it can be read directly but can be
writen only by call member function.
You can use Borland's proprietary '__property' keyword, ie:
class MyClass
{
private:
int val;
void __fastcall SetValue(int newval)
{
//...
val = newvalue;
//...
}
public:
__property int Value = {read=val, write=SetValue};
};
Quote
I don't want to make it as a private variable since there are
too many changes to current codes if do so.
Making it private is the only way to prevent it from being directly
writable. Using the __property keyword, you can name the property anything
you wish, so make the actual variable private so it is not directly
accessible, then rename it for class's internal use, and then finally name
the property the same name as the old variable name.
Gambit
 

{smallsort}

Re:read-only class member variable

"Remy Lebeau \(TeamB\)" < XXXX@XXXXX.COM >wrote:
Quote
You can use Borland's proprietary '__property' keyword, ie:

class MyClass
{
private:
int val;
void __fastcall SetValue(int newval)
{
//...
val = newvalue;
//...
}
public:
__property int Value = {read=val, write=SetValue};
};

Hi Gambit
Thanks. It should work for me. My variable type is char array.
I got compile error: "array property missing ]"
Here is the code. what's wrong?
public:
__property char name[32] = {read=devName, write=SetName};
virtual void __fastcall SetName(char*newName)
{strcpy(devName,newName);};
private:
char devName[32];
 

Re:read-only class member variable

didan wrote:
Quote
My variable type is char array.
I got compile error: "array property missing ]"
Here is the code. what's wrong?
public:
__property char name[32] = {read=devName, write=SetName};
name[32] would be the 33th element of the array.
This construction is not possible. Besides you use
strcpy() instead of strncpy ( , 32 - 1) and placeing
a terminating zero.
All in all better use AnsiString:
private:
AnsiString devName;
void SetName(AnsiString newName)
{
devName = newName;
}
public:
__property AnsiString Name = {read=devName, write=SetName } ;
Hans,
 

Re:read-only class member variable

"didan" < XXXX@XXXXX.COM >wrote in message
Quote
Thanks. It should work for me. My variable type is char array.
I wish you had said that earlier. You cannot use char[] with properties.
You will have to use char* instead, ie:
public:
__property char* name = {read = devName, write = SetName};
protected:
virtual void __fastcall SetName(char* newName)
{
strncpy(devName, newName, 32);
}
private:
char devName[32];
Gambit
 

Re:read-only class member variable

Remy Lebeau (TeamB) wrote:
Quote
public:
__property char* name = {read = devName, write = SetName};
In bcb5 this does not compile.
//[C++ Error] Unit1.cpp(75): E2347 Parameter mismatch
//in read access specifier of property name
To use a real char pointer:
__property char* name = {read = devNamePtr, write = SetName};
and
private:
char devName[32];
char *devNamePtr;
But then you need a constructor that innitialises
devNamePtr with the address of the first byte of devName[];
Aclass(){devNamePtr = devName;}
Quote
protected:
virtual void __fastcall SetName(char* newName)
{
strncpy(devName, newName, 32);
add here a terminating zero:
devName [32-1] = 0;
For a test: mit the statement and see what it does in:
void __fastcall TForm1::Button2Click(TObject *Sender)
{
Aclass aclass;
aclass.name = "aaaaaaaaab ddddddddddd ggggggggggg hhhhhhhh iiiiii";
ShowMessage ( aclass.name );
}
Hans.
 

Re:read-only class member variable

"Hans Galema" < XXXX@XXXXX.COM >wrote in message
Quote
In bcb5 this does not compile.

//[C++ Error] Unit1.cpp(75): E2347 Parameter mismatch
//in read access specifier of property name
You will just have to use a getter method then:
public:
__property char* name = {read = GetName, write = SetName};
protected:
char* __fastcall GetName()
{
return devName;
}
virtual void __fastcall SetName(char* newName)
{
strncpy(devName, newName, 32);
}
private:
char devName[32];
Quote
add here a terminating zero:

devName [32-1] = 0;
strncpy() already null-terminates the buffer, as long as the buffer has
enough space available. If the source string is>= 32 characters, the null
terminator will not be written, unless 31 is specified to strncpy() instead
of 32.
Gambit
 

Re:read-only class member variable

Remy Lebeau (TeamB) wrote:
Quote
You will just have to use a getter method then:
Indeed that is good solution then.
Quote
strncpy() already null-terminates the buffer, as long as the buffer has
enough space available. If the source string is>= 32 characters, the null
terminator will not be written, unless 31 is specified to strncpy() instead
of 32.
No. strncpy does not add a zero. And the buffer is filled at random
at first. strncpy just copies the amount of bytes specified.
If one of them is a zero strncpy copies that one also and then stops.
So it is not guaranteed that there is a terminating
zero. For that
devName [32-1] = 0;
is always needed.
Hans.
 

Re:read-only class member variable

"Hans Galema" < XXXX@XXXXX.COM >wrote in message
Quote
No. strncpy does not add a zero.
Yes, it does:
"strncpy copies up to maxlen characters from src into dest, truncating
***or null-padding dest.**"
Notice the last part. Any remaining space in the buffer after the copy is
finished gets initialized with zeros. Here is a test to prove it:
char buffer[32];
memset(buffer, ' ', 32);
strncpy(buffer, "test", 32);
Characters 4-31 have been changed from ' ' to '\0'. Please refer back to my
earlier comment:
"strncpy() already null-terminates the buffer, ***as long as the buffer
has enough space available.***"
Quote
And the buffer is filled at random at first.
Only if you do not initialize it yourself before calling strncpy(). You
should always initialize your buffers before using them.
Quote
strncpy just copies the amount of bytes specified.
It does more than that.
Quote
So it is not guaranteed that there is a terminating zero.
If the buffer is large enough to contain the full source string and a
terminator, then yes, the terminator *is* guaranteed, as long as you specify
that much space is available when passing the buffer's size to strncpy().
Quote
devName [32-1] = 0;

is always needed.
It is not always needed. Only when the length of the source string is>=
the size of the buffer. You can account for that, though:
char devName[33] = {0};
strncpy(devName, "some string", 32);
Gambit
 

Re:read-only class member variable

Remy Lebeau (TeamB) wrote:
Quote
Yes, it does:

"strncpy copies up to maxlen characters from src into dest, truncating
***or null-padding dest.**"
Indeed it does.
Quote
"strncpy() already null-terminates the buffer, ***as long as the buffer
has enough space available.***"
For me that is the null-terminator of src.
Quote
>And the buffer is filled at random at first.
Only if you do not initialize it yourself before calling strncpy(). You
should always initialize your buffers before using them.
And because you did not in your post for didan I reacted.
But then initialize *before* is not needed. In fact I never do that.
Just as good is placing a terminating zero as I proposed.
Hans.
 

Re:read-only class member variable

"Remy Lebeau \(TeamB\)" < XXXX@XXXXX.COM >writes:
Quote
virtual void __fastcall SetName(char* newName)
{
strncpy(devName, newName, 32);
}
strncpy() already null-terminates the buffer, as long as the buffer has
enough space available. If the source string is>= 32 characters, the null
terminator will not be written, unless 31 is specified to strncpy() instead
of 32.
Which is why I like to write code like this:
strncpy(devName, newName, SIZE);
devName[SIZE-1] = '\0';
Just in case the trailing null is missing...
Though the C99 spec always null terminates the function results,
regardless of truncation. So worrying about this will likely become
archaic eventually, when/if C++ adopts C99 features.
--
Chris (TeamB);
 

Re:read-only class member variable

Hans Galema < XXXX@XXXXX.COM >writes:
Quote
Remy Lebeau (TeamB) wrote:

>You will just have to use a getter method then:

Indeed that is good solution then.

>strncpy() already null-terminates the buffer, as long as the buffer has
>enough space available. If the source string is>= 32 characters, the null
>terminator will not be written, unless 31 is specified to strncpy() instead
>of 32.

No. strncpy does not add a zero. And the buffer is filled at random
strncpy will null-terminate a buffer whenver it's called UNLESS you
ask it to write more data than the buffer can hold.
Quote
So it is not guaranteed that there is a terminating
zero. For that

devName [32-1] = 0;

is always needed.
I agree you need to write code like that (well, '\0' is one byte,
while 0 is an int requiring a conversion...), but in the case that the
buffer is large enough, this is just precaution. In the case where
the buffer is not big enough, you need to do this. Since it's hard to
know in advance if the buffer will be big enough or not, it's an
unwritten rule to always write a '\0' to that last byte. The overhead
is minimal, and sometimes it prevents bugs.
--
Chris (TeamB);
 

Re:read-only class member variable

Quote
Which is why I like to write code like this:
Great Minds!
One function in my private libs that I use all the time is SafeStrncpy.
Three guesses what it does <g>
. Ed
Quote
Chris Uzdavinis wrote in message
news: XXXX@XXXXX.COM ...

Which is why I like to write code like this:

strncpy(devName, newName, SIZE);
devName[SIZE-1] = '\0';

Just in case the trailing null is missing...

Though the C99 spec always null terminates the function results,
regardless of truncation. So worrying about this will likely become
archaic eventually, when/if C++ adopts C99 features.
 

Re:read-only class member variable

Chris Uzdavinis (TeamB) wrote:
Quote
.... (well, '\0' is one byte,
while 0 is an int requiring a conversion...),
This remark will change my future code.
Thanks.
Hans.