Trivial Property not working
-
I'm getting really confused by trivial properties. Can someone explain this to me:
#include "stdafx.h"
using namespace System;
ref class Foo
{
public:
// default constructor, initializes data members to non null values
Foo()
{
data = 0;
s = "default";
}
// constructor with 2 parameters, initializes data members to non null values
Foo(int d, String^ in)
{
data = d;
s = in;
}
virtual String^ ToString() override
{
return "Data: " + this->Data + " S: " + this->S;
}// I'm writing the properties explicitly
// In theory, there is no reason I shouldn't be able to use trivial property
// declarations in place of these two
property int Data
{
int get()
{
return data;
}
void set(int d )
{
data = d;
}}
property String^ S
{
String^ get()
{
return s;
}
void set(String^ in)
{
s = in;
}
}
// The trivial property declarations which are giving me trouble when I try to use them
// property int Data;
// property String^ S;// This is commented out just for demonstration purposes
// With the current code these could be made private and things would still work
// private:
int data;
String^ s;
};int main(array ^args)
{
// create Foo objects in a bunch of ways
// none of them should have any null members
Foo f;
Foo b(1, "hello");
Foo ^c = gcnew Foo(5, "world");// this will obviously fail if you make the data members private // In the current form, this prints out the correct values Console::WriteLine(f.data + " " + f.s->ToString()); Console::WriteLine(b.data + " " + b.s->ToString()); Console::WriteLine(c->data + " " + c->s->ToString()); // This block prints correctly when using the explicit property declarations currently in use // whether the data members are private or public. // If I use the trivial property declarations (currently commented out) instead // then this block causes NullReferenceExceptions when trying to access S. // If I debug I notice that the for each member made by the trivial property // is not being set but there is a properly set Data and S field. Console::WriteLine(f.Data + " " + f.S->ToString()); Console::WriteLine(b.Data + " " + b.S->ToString()); Console::WriteLine(c->Data + " "
-
I'm getting really confused by trivial properties. Can someone explain this to me:
#include "stdafx.h"
using namespace System;
ref class Foo
{
public:
// default constructor, initializes data members to non null values
Foo()
{
data = 0;
s = "default";
}
// constructor with 2 parameters, initializes data members to non null values
Foo(int d, String^ in)
{
data = d;
s = in;
}
virtual String^ ToString() override
{
return "Data: " + this->Data + " S: " + this->S;
}// I'm writing the properties explicitly
// In theory, there is no reason I shouldn't be able to use trivial property
// declarations in place of these two
property int Data
{
int get()
{
return data;
}
void set(int d )
{
data = d;
}}
property String^ S
{
String^ get()
{
return s;
}
void set(String^ in)
{
s = in;
}
}
// The trivial property declarations which are giving me trouble when I try to use them
// property int Data;
// property String^ S;// This is commented out just for demonstration purposes
// With the current code these could be made private and things would still work
// private:
int data;
String^ s;
};int main(array ^args)
{
// create Foo objects in a bunch of ways
// none of them should have any null members
Foo f;
Foo b(1, "hello");
Foo ^c = gcnew Foo(5, "world");// this will obviously fail if you make the data members private // In the current form, this prints out the correct values Console::WriteLine(f.data + " " + f.s->ToString()); Console::WriteLine(b.data + " " + b.s->ToString()); Console::WriteLine(c->data + " " + c->s->ToString()); // This block prints correctly when using the explicit property declarations currently in use // whether the data members are private or public. // If I use the trivial property declarations (currently commented out) instead // then this block causes NullReferenceExceptions when trying to access S. // If I debug I notice that the for each member made by the trivial property // is not being set but there is a properly set Data and S field. Console::WriteLine(f.Data + " " + f.S->ToString()); Console::WriteLine(b.Data + " " + b.S->ToString()); Console::WriteLine(c->Data + " "
Maybe I'm missing something, but how can you expect to read a property if you omit the getter function? Also, is using ToString on a String redundant? :) Mark
Mark Salsbery Microsoft MVP - Visual C++ "Go that way, really fast. If something gets in your way, turn."
-
Maybe I'm missing something, but how can you expect to read a property if you omit the getter function? Also, is using ToString on a String redundant? :) Mark
Mark Salsbery Microsoft MVP - Visual C++ "Go that way, really fast. If something gets in your way, turn."
Unless I'm horribly mistaken... Declaring the trivial property as follows:
property int Data;
should tell the compiler to generate something to the effect of:
property int Data
{
int get()
{
return data;
}
void set(int d)
{
data = d;
}
}using a ' < backing_store > Data' variable behind the scenes. Likewise for
property String^ S
That's the whole point of trivial properties as I understood it. If you're just making a 'trivial' getter and setter with no validation then the trivial property declaration should accomplish what you need and save you from typing a few lines of code. At least that's what I gathered from http://www.codeproject.com/managedcpp/CppCliProperties.asp?df=100&forumid=179807&exp=0&select=1107337 and many other articles/books. And yes, that was a little redundant :~ I've been staring at this property stuff for so long I'm making some dumb mistakes and triple checking everything before I post it. -- modified at 18:18 Tuesday 3rd July, 2007
-
I'm getting really confused by trivial properties. Can someone explain this to me:
#include "stdafx.h"
using namespace System;
ref class Foo
{
public:
// default constructor, initializes data members to non null values
Foo()
{
data = 0;
s = "default";
}
// constructor with 2 parameters, initializes data members to non null values
Foo(int d, String^ in)
{
data = d;
s = in;
}
virtual String^ ToString() override
{
return "Data: " + this->Data + " S: " + this->S;
}// I'm writing the properties explicitly
// In theory, there is no reason I shouldn't be able to use trivial property
// declarations in place of these two
property int Data
{
int get()
{
return data;
}
void set(int d )
{
data = d;
}}
property String^ S
{
String^ get()
{
return s;
}
void set(String^ in)
{
s = in;
}
}
// The trivial property declarations which are giving me trouble when I try to use them
// property int Data;
// property String^ S;// This is commented out just for demonstration purposes
// With the current code these could be made private and things would still work
// private:
int data;
String^ s;
};int main(array ^args)
{
// create Foo objects in a bunch of ways
// none of them should have any null members
Foo f;
Foo b(1, "hello");
Foo ^c = gcnew Foo(5, "world");// this will obviously fail if you make the data members private // In the current form, this prints out the correct values Console::WriteLine(f.data + " " + f.s->ToString()); Console::WriteLine(b.data + " " + b.s->ToString()); Console::WriteLine(c->data + " " + c->s->ToString()); // This block prints correctly when using the explicit property declarations currently in use // whether the data members are private or public. // If I use the trivial property declarations (currently commented out) instead // then this block causes NullReferenceExceptions when trying to access S. // If I debug I notice that the for each member made by the trivial property // is not being set but there is a properly set Data and S field. Console::WriteLine(f.Data + " " + f.S->ToString()); Console::WriteLine(b.Data + " " + b.S->ToString()); Console::WriteLine(c->Data + " "
Here's my other test case that is confusing the hell out of me. The errors/results/questions are all in the comments:
#include "stdafx.h"
using namespace System;
// managed class with explicity copy constructor and assignment operator
ref class Foo
{
public:
Foo() {} // default constructor// constructor takes a single parameter
// intialize value data member via direct access or through property
Foo(int d)
{
Value = d; // (3)
//value = d; // (4)
}
// copy constructor
// could declare parameter const but then you can't use Value property
Foo(Foo^ b) //: value(b->value) Initializer presumably doesn't work for the same reasons
{
//Value = b->Value; // (1)
value = b->value; // (2)
//value = b->Value; // Presumably doesn't work for the same reasons
}// trivial property declaration, in theory creates the same code as the explicit below
property int Value;// explicit property declaration
/*property int Value
{
int get()
{
return value;
}
void set(int v)
{
value = v;
}
}*/// note: value must be public for Block B to work.
// Public or private doesn't affect the following results.//private:
int value;
};int main (array ^)
{
// **************************************************************************
// The following results are based on using the default constructor
// and setting the value member after construction
// Define 'works' to mean the copy constructor properly initializes the
// value data member of the new Foo object to be equal to the value in the passed argument
/* If the copy constructor uses (1) instead of (2):
* TRIVIAL PROPERTY DECLARED: Block A works, Block B doesn't work
* EXPLICIT PROPERTY DECLARED: Block A works, Block B works\* If the copy constructor uses (2) instead of (1): \* TRIVIAL PROPERTY DECLARED: Block A doesn't work, Block B works \* EXPLICIT PROPERTY DECLARED: Block A works, Block B works \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/
// *****************************************************************************
// The following results are based on using the single parameter constructor
// to set the value data member
/* If the single parameter constructor uses (4) instead of (3):
* TRIVIAL PROPERTY DECLARED: Block A doesn't work, Block B wor -
Unless I'm horribly mistaken... Declaring the trivial property as follows:
property int Data;
should tell the compiler to generate something to the effect of:
property int Data
{
int get()
{
return data;
}
void set(int d)
{
data = d;
}
}using a ' < backing_store > Data' variable behind the scenes. Likewise for
property String^ S
That's the whole point of trivial properties as I understood it. If you're just making a 'trivial' getter and setter with no validation then the trivial property declaration should accomplish what you need and save you from typing a few lines of code. At least that's what I gathered from http://www.codeproject.com/managedcpp/CppCliProperties.asp?df=100&forumid=179807&exp=0&select=1107337 and many other articles/books. And yes, that was a little redundant :~ I've been staring at this property stuff for so long I'm making some dumb mistakes and triple checking everything before I post it. -- modified at 18:18 Tuesday 3rd July, 2007
:) It's me that's horribly mistaken. When you initialize the trivial proprties in your constructors, you need to use the trivial property names:
// default constructor, initializes data members to non null values
Foo()
{
Data = 0;
S = "default";
}// constructor with 2 parameters, initializes data members to non null values
Foo(int d, String^ in)
{
Data = d;
S = in;
}
...
property int Data;
property String^ S;Mark
Mark Salsbery Microsoft MVP - Visual C++ "Go that way, really fast. If something gets in your way, turn."
-
:) It's me that's horribly mistaken. When you initialize the trivial proprties in your constructors, you need to use the trivial property names:
// default constructor, initializes data members to non null values
Foo()
{
Data = 0;
S = "default";
}// constructor with 2 parameters, initializes data members to non null values
Foo(int d, String^ in)
{
Data = d;
S = in;
}
...
property int Data;
property String^ S;Mark
Mark Salsbery Microsoft MVP - Visual C++ "Go that way, really fast. If something gets in your way, turn."
Right, I just didn't see why simply declaring the trivial property (instead of an explicit getter and setter) caused accessing the member variables directly not to work. Nor had I ever seen mention of this fact. If declaring a property makes it so you can't access the member properly without it that seems like something that should've been mentioned somewhere...
-
Right, I just didn't see why simply declaring the trivial property (instead of an explicit getter and setter) caused accessing the member variables directly not to work. Nor had I ever seen mention of this fact. If declaring a property makes it so you can't access the member properly without it that seems like something that should've been mentioned somewhere...
You can access them. Using your code only failed for me when using the trivial properties because the constructors were setting the non-trivial property variable names (actually they weren't even properties at that point - they're just member variables). That left the trivial property "S" uninitialized, causing a NULL exception when accessed. Once you get rid of these variables // private: int data; String^ s; and access these instead property int Data; property String^ S; it works fine. For me it was a good example of why having two variable names that differ only in case is a recipe for disaster :) Mark
Mark Salsbery Microsoft MVP - Visual C++ "Go that way, really fast. If something gets in your way, turn."
-
Here's my other test case that is confusing the hell out of me. The errors/results/questions are all in the comments:
#include "stdafx.h"
using namespace System;
// managed class with explicity copy constructor and assignment operator
ref class Foo
{
public:
Foo() {} // default constructor// constructor takes a single parameter
// intialize value data member via direct access or through property
Foo(int d)
{
Value = d; // (3)
//value = d; // (4)
}
// copy constructor
// could declare parameter const but then you can't use Value property
Foo(Foo^ b) //: value(b->value) Initializer presumably doesn't work for the same reasons
{
//Value = b->Value; // (1)
value = b->value; // (2)
//value = b->Value; // Presumably doesn't work for the same reasons
}// trivial property declaration, in theory creates the same code as the explicit below
property int Value;// explicit property declaration
/*property int Value
{
int get()
{
return value;
}
void set(int v)
{
value = v;
}
}*/// note: value must be public for Block B to work.
// Public or private doesn't affect the following results.//private:
int value;
};int main (array ^)
{
// **************************************************************************
// The following results are based on using the default constructor
// and setting the value member after construction
// Define 'works' to mean the copy constructor properly initializes the
// value data member of the new Foo object to be equal to the value in the passed argument
/* If the copy constructor uses (1) instead of (2):
* TRIVIAL PROPERTY DECLARED: Block A works, Block B doesn't work
* EXPLICIT PROPERTY DECLARED: Block A works, Block B works\* If the copy constructor uses (2) instead of (1): \* TRIVIAL PROPERTY DECLARED: Block A doesn't work, Block B works \* EXPLICIT PROPERTY DECLARED: Block A works, Block B works \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/
// *****************************************************************************
// The following results are based on using the single parameter constructor
// to set the value data member
/* If the single parameter constructor uses (4) instead of (3):
* TRIVIAL PROPERTY DECLARED: Block A doesn't work, Block B wor"property int Value;" creates it's own member variable to store the value, it won't use "int value;". So you got two members (one property "Value" and one field "value") that are unrelated and store different values.
-
"property int Value;" creates it's own member variable to store the value, it won't use "int value;". So you got two members (one property "Value" and one field "value") that are unrelated and store different values.
So it seems. I'm just confused because all the postings I've seen about it have said you can write a trivial property declaration just like I did in place of the type of explicit one that I did (i.e., no mention of making sure to name the trivial property differently). It makes it incredibly confusing if your trivial property has the exact same name (case and all) as a data member... so confusing as to be useless in my opinion...