"pointers" in /clr

P

Peter Oliphant

In the 'old days', we could create a pointer to an instance of a variable
like so:

int i = 58 ;
int* i_ptr = &i ;
int j = *i_ptr ; // j = 58

Now, in /clr how do we do the same? That is, if I replace '*' with '^' what
do I replace '&' with to generate a 'pointer' (is 'x^' called a 'reference'
per chance?) to the instance? That is:

ref class myClass() {...} ;

myClass i ;
myClass^ i_ptr = &i ; // error, use what instead of '&'?
myClass j = *i_ptr ; // error (i think), do what instead?

[==P==]
 
H

Holger Grund

Peter Oliphant said:
ref class myClass() {...} ;

myClass i ;
myClass^ i_ptr = &i ; // error, use what instead of '&'?
myClass^ i_ptr = %i;
myClass j = *i_ptr ; // error (i think), do what instead?
That's fine, so long as a copy ctor is defined. C++/CLI
does _not_ automatically define copy ctors for ref classes
* sigh *.

If you want
the equivalent to a C++ reference (int%) you can write
myClass% j = *i_ptr;

-hg
 
P

Peter Oliphant

Hi Holger,

In fact, the reason I asked was because I needed to create a copy
constructor and I couldn't without knowing these syntax 'equivalences' to
'pointer' and 'contents of'... : )

That is, I didn't know this is the form of a copy constructor for a ref
class:

ref class refClass
{
refClass( refClass% other ) {}
} ;


[==P==]
 
B

beginthreadex

Syntax like this in anything that's called C++ is so frustrating. What you
have below is just garbage ... and I wish Microsoft would collect it.
 
N

Nishant Sivakumar

Hey Peter

Just want to add that ref classes also don't get a default assignment
operator.

--
Regards,
Nish [VC++ MVP]


Peter Oliphant said:
Hi Holger,

In fact, the reason I asked was because I needed to create a copy
constructor and I couldn't without knowing these syntax 'equivalences' to
'pointer' and 'contents of'... : )

That is, I didn't know this is the form of a copy constructor for a ref
class:

ref class refClass
{
refClass( refClass% other ) {}
} ;


[==P==]

Holger Grund said:
myClass^ i_ptr = %i;

That's fine, so long as a copy ctor is defined. C++/CLI
does _not_ automatically define copy ctors for ref classes
* sigh *.

If you want
the equivalent to a C++ reference (int%) you can write
myClass% j = *i_ptr;

-hg
 
W

William DePalo [MVP VC++ ]

beginthreadex said:
Syntax like this in anything that's called C++ is so frustrating. What you
have below is just garbage ... and I wish Microsoft would collect it.

That's one opinion. Here is another:

If one's goal is to develop a native application in standard C++ then the
new syntax is beside the point as it will not be present.

On the other hand, if one targets a platform whose objects are allowed to
move around in memory without the knowledge or consent of the developer or
his language, then it is unreasonable to assume that the standard language,
which makes no provision for such movement, will be expressive enough
without changes.

Regards,
Will
 
B

beginthreadex

The frustrating part is that articles from Microsoft do not designate they
are for managed code only. There are many C++ articles out there and if
they are for Managed code then they need to state so. "MC++" would be VERY
acceptable! Please !!

Persons that have been developing in VC++ for many years might run into the
same issues that I do with my teams. If MS knows that the classes are
collected then the syntax should not matter. There should be no reason for
^ instead of * or % instead of &. Just stick to what's already trained into
people so we don't need to keep rewritting things but use all the tools.

If not, then at least really embrace the __gc and such because that looks
and feels more standard.

Personally, I feel that Microsoft did a great job with .NET and C++.NET/MC++
is awesome. It's not for all tasks but it's something to be very proud of
in the end. It will be more impressive when the Phoenix compiler is
complete and we can actually compile to native with all of these "cool
helper classes".
 
P

Peter Oliphant

I need to return a pointer to a member of a ref class. I can do this in 2003
(return the address of a class member), hopefully this functionality has not
been removed or disallowed in 2005, as my entire design depends on this
ability. To make this problem concrete:

ref class myClass()
{
public:
myClass() {}
~myClass() {}
int X ;
int* X_Ptr() { return &X ; } // error
int^ X_Ptr() { return %X ; } // error
} ;

Assume only one X_Ptr() exists in myClass, I'm just listing both syntaxes
that cause an error in one place for clarity. How do I do this?

Thanks in advance for responses!

[==P==]

Nishant Sivakumar said:
ref class R
{
. . .
};

. . .

R r1;
R^ r2 = %r1;
R% r3 = *r2;

--
Regards,
Nish [VC++ MVP]


Peter Oliphant said:
In the 'old days', we could create a pointer to an instance of a variable
like so:

int i = 58 ;
int* i_ptr = &i ;
int j = *i_ptr ; // j = 58

Now, in /clr how do we do the same? That is, if I replace '*' with '^'
what do I replace '&' with to generate a 'pointer' (is 'x^' called a
'reference' per chance?) to the instance? That is:

ref class myClass() {...} ;

myClass i ;
myClass^ i_ptr = &i ; // error, use what instead of '&'?
myClass j = *i_ptr ; // error (i think), do what instead?

[==P==]
 
H

Holger Grund

Peter Oliphant said:
ref class myClass()
{
public:
myClass() {}
~myClass() {}
int X ;
int* X_Ptr() { return &X ; } // error
int^ X_Ptr() { return %X ; } // error
} ;

Assume only one X_Ptr() exists in myClass, I'm just listing both syntaxes
that cause an error in one place for clarity. How do I do this?
If you want what the CLR calls a "managed pointer" you
can use

interior_ptr<int> X_ptr() { return &X; }

Manage pointers are not affected by the GC relocation the
objects pointed to.
Interior pointer can't have static storage duration.

If you want a native pointer, you have to pin the object
pointed to by using a pin_ptr.

int* X_Ptr() { pin_ptr<int> p (&X);return p; }

Oc, you should make sure the object is still pinned
when the native pointer is used ( not the case in the
example above!).

-hg
 
T

Tamas Demjen

beginthreadex said:
Persons that have been developing in VC++ for many years might run into the
same issues that I do with my teams. If MS knows that the classes are
collected then the syntax should not matter. There should be no reason for
^ instead of * or % instead of &. Just stick to what's already trained into
people so we don't need to keep rewritting things but use all the tools.

Unfortunately there are substantial differences between the native and
the managed OOP paradigm. The .NET framework doesn't support global
variables and functions at all, it only knows methods and properties.
Although C++/CLI has stack syntax, the framework only supports pointer
(handle) syntax for ref classes, and value classes are severely limited.
In the managed world, there's no concept for const (in particular,
global constants, const member functions), which is IMHO is a very big
problem, but this is what we have. Heck, even the concept of destructors
doesn't exist in the managed world, and C++/CLI destructors are not 100%
compatible with the standard ones. The concept of default argument
doesn't exist either. Should I go on? Virtual functions must be
explicitly declared "override" if they override an existing one. There
is no operator overloading either.

On the other hand, native C++ doesn't have the concept of properties,
delegates, events, and most importantly, the concept of public and
private classes. Every class that's #include'ed is public, what's not in
the headers is private.

Even though it sounds nice in theory to be able to share the same code
base between the native and the managed worlds, it's almost never
technically possible. You can't write anything more than trivial that
you could share between native C++ and managed C++. I agree that the old
MC++ syntax looked like you could share trivial code between the two,
but I don't think it was practical in real-world applications or
libraries. You would have to be very careful to use only that narrow
common feature set that both worlds have, and even then you have to deal
with the class visibility issue. "public class" doesn't compile under
std C++, but a simple "class" means private in old MC++, which is not
what you want. The old MC++ syntax may give you a false sense of
security that you can theoretically write code for both worlds, when in
practice it almost never happens.

I question myself if it would have made sense to create C++/CLI so that
you could share code between the two world. When you could really write
it once and compile standard native C++ code into pure managed
assemblies. Such as disregarding the const keyword in managed mode.
Setting up the default class visibility using a #pragma class public, or
something similar. Automatically inserting the "override" keyword for
virtual methods that override existing ones. Keeping the * and & symbols
for managed handles and references. Automatically substituting static
const members with read-only properties. Automatically substituting
default arguments with function overriding for .NET. Automatically
substitute getter and setter functions with properties. And so on and so
forth. But C++ is a low-level language, and these hidden translations in
the background would certainly mean losing control. You still wouldn't
be able to do everything, you'd still need to #ifdef a whole bunch of
lines. You still wouldn't be able to use events in native C++ the exact
same way as delegates work in .NET, even though similar concepts
(boost::function) now exist in standard C++. It's impossible to
translate every unmanaged C++ code to .NET anyway.

Quite frankly, I don't think this was their goal with C++/CLI. They
wanted a language where you

1) have low-level, but full support for almost every .NET framework
feature, with a language as similar to C++ as possible

2) can freely intermix managed and unmanaged code, and for that it was a
very good idea to introduce the ^ and % symbols. It's way less confusing
than __gc * and __nogc *. I love that T ^ is managed and U * is
unmanaged, and I can tell that in an instant.

But I'm hearing you, sometimes it would be very nice to compile native
C++ code into pure managed, without having to rewriting a single line,
even if there are severe restrictions with that. Maybe someone will
write a standard C++ to C++/CLI code converter. After all, Borland
created a mechanism for automatically generating a C++ header file from
a Pascal input, and with few limitations it works perfectly (only Pascal
is trivial to parse, C++ is far from it). I can imagine an automated
native to managed converter would work with restrictions, so we could
write once and reuse the code twice. I could imagine converting
boost::shared_ptr<T> to T^, and boost::function to delegates, and so on.
The question is how much market it has, because it's quite some work to
write such a compiler.

In practice, when you program for .NET you use framework types and
functions, such as Drawing::Color, Rectangle, String, and .NET
collections. How far are you willing to go with the automatic type
substitution? I don't think it's feasable to really write your code once
and reuse it for native C++ and .NET at the same time. You're pretty
much forced to rewrite it, or to wrap unmanaged code into managed classes.

Tom
 
W

William DePalo [MVP VC++ ]

beginthreadex said:
The frustrating part is that articles from Microsoft do not designate they
are for managed code only.

Hmm.

What I agree is confusing is tagging everything with the .Net moniker. We
sometimes get questions here as to whether Visual Studio .Net includes a
"real" C++ compiler. The truth is that it in effect includes four
compilers - C, C++ for native applications and Managed C++ and C++/CLI for
managed code.

On the other hand, it is hard to imagine an article on the new syntax not
being couched in .Net terms.
Persons that have been developing in VC++ for many years might run into
the
same issues that I do with my teams. If MS knows that the classes are
collected then the syntax should not matter.

They tried going down this path. We told them that we hated it. They
listened. In fact the point can be made that things are _less_ confusing
now: the new operator is a used to allocate and initialize native objects
while gcnew is used for managed objects. Here the departure from the norm
makes the intent crystal clear.

Regards,
Will
 
B

beginthreadex

I really liked what you said Tom. It gives me great pause and I'll have to
think about some of the things you have said. With that, you have a
perspective that I am only starting to understand by reading your article.

Honestly, I have hated the new c++.net because of some many reasons. When
you approach this new language from the perspective of your statements I
must say that it does compell me to finally give c++.net a SERIOUS look.
And as any titilated programmer I will start my personal review today ...
thinking from your perspective. Interesting. Different. Not competing.

Thanks again for your time and all that you have said. I plan on printing
this out and re-reading over your words in detail.
 
T

Tamas Demjen

Tamas said:
Automatically substituting
default arguments with function overriding for .NET.

Overloading I meant. To implement something similar to default arguments
in .NET you overload, not override.

Tom
 
T

Tamas Demjen

beginthreadex said:
I really liked what you said Tom. It gives me great pause and I'll have to
think about some of the things you have said.

When I first heard of STL.NET, I thought it would be nearly 100%
compatible with the STL, except it would generate managed code. When I
first read the STL Primer article, I was quite disappointed that it had
managed syntax. First I thought that again, I wouldn't be able to write
my code once and compile it for native C++ and /clr:pure at the same
time. But very soon it became clear that it was not the goal at all.
STL.NET was created to access .NET collections in the spirit of STL
containers. We've spent a lot of time getting familiar with STL, and it
would be nice to use a very similar API for .NET. The whole purpose is
to not having to re-learn another API from scratch; and not to reuse
existing code unmodified to generate pure managed output.

There are two more important aspects I missed from my original post:

1. strings. System::String is immutable -- you can't modify its
contents. Every method that modifies the string is static and
returns a brand new copy. This is a totally different concept than in
std::string. Another reason why you can't write your code once and reuse
it in both worlds.

2. In .NET you can't have private virtual functions. At least the
compiler shows an error if I try that. It's usual practice in C++ that
if a virtual function won't be called from descendants, you make it
private by default. In .NET, you can't. It's another limitation, another
reason to rewrite all existing native code, or to wrap, but not to reuse.

Tom
 
B

Brandon Bray [MSFT]

I've enjoyed reading this thread; I haven't had the opportunity to read
newsgroups lately.

Tamas said:
2. In .NET you can't have private virtual functions. At least the
compiler shows an error if I try that. It's usual practice in C++ that
if a virtual function won't be called from descendants, you make it
private by default. In .NET, you can't. It's another limitation, another
reason to rewrite all existing native code, or to wrap, but not to
reuse.

You can partly blame no private virtual functions on me. Here's the scoop...
the CLR does not allow overriding virtual functions in ref classes to reduce
the visibility of a function. In other words, a private virtual function
cannot override a public virtual function. That's because it can always be
called from the base class... it's not actually private.

With that said, private virtual functions are not really useful. They can't
be overridden because an overriding virtual function in a ref class must
have the ability to call the function it's overriding.

You can have a private virtual sealed function though. That's only useful
for explicit interface implementations. For example:

interface class I {
void F();
};

ref class R {
virtual void G() sealed = I::F;
};

In general, there are a lot of practices that private functions enabled in
native classes that no longer work in ref classes. We thought through as
many as we could and provided alternatives. While preventing a function in a
base class from being called by a derived class can't be enforced (even with
native classes), there are two features worth noting:
1. Sealed functions allow a base class to prevent a derived class from
overriding specific functions.
2. New functions allow a derived class to use the same name and signature
as a function in a base class without overriding that function. This
could be used to achieve something like the desired scenario.

Hope that helps!
 
T

Tamas Demjen

Brandon said:
You can partly blame no private virtual functions on me. Here's the scoop...
the CLR does not allow overriding virtual functions in ref classes to reduce
the visibility of a function. In other words, a private virtual function
cannot override a public virtual function. That's because it can always be
called from the base class... it's not actually private.

Thanks, Brandon, for the clarification, it makes sense. I'm thinking
with a native C++ head, so I still have to get used to these new
concepts. I can't wait till a good C++/CLI book finally hits the stores.

Of course there is no blame on my side. If I was to be unhappy about
anything at all, that would be the lack of const member functions in the
..NET framework. It's like a step back to us C++ programmers. I
understand that it may be addressed in a future version.

Tom
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top