Nonstatic member example?

F

fl

Hi,
There is a question about nonstatic member. C++ primer says: A
nonstatic member is restricted to being declared as a pointer or
reference to an object of its class. It only gives an example of
pointer *b.

class Bar {
public:

private:
static Bar a; // OK
Bar *b; // OK
Bar c; // error

My question is how a nonstatic member is declared as a reference to an
object of its class. Because a reference is legal only after the
original variable has been declared, where is the original object? I
feel it is really bizarre. Could you give me an example? Thanks in
advance.




private variable
 
J

Juha Nieminen

fl said:
Hi,
There is a question about nonstatic member. C++ primer says: A
nonstatic member is restricted to being declared as a pointer or
reference to an object of its class. It only gives an example of
pointer *b.

class Bar {
public:

private:
static Bar a; // OK
Bar *b; // OK
Bar c; // error

My question is how a nonstatic member is declared as a reference to an
object of its class. Because a reference is legal only after the
original variable has been declared, where is the original object? I
feel it is really bizarre. Could you give me an example? Thanks in
advance.

References and pointers can be created from pre-declared (ie.
incomplete) types. It's not necessary to have the full declaration of
the type in order to create a reference or pointer of that type. That
is, for example, this is valid:

class A; // Incomplete type

void foo(const A&); // Ok

In your example "Bar" has implicitly been pre-declared, and thus it's
ok to create a reference of pointer to it, even inside Bar's declaration.
 
J

Jim Langston

fl said:
Hi,
There is a question about nonstatic member. C++ primer says: A
nonstatic member is restricted to being declared as a pointer or
reference to an object of its class. It only gives an example of
pointer *b.

class Bar {
public:

private:
static Bar a; // OK
Bar *b; // OK
Bar c; // error

My question is how a nonstatic member is declared as a reference to an
object of its class. Because a reference is legal only after the
original variable has been declared, where is the original object? I
feel it is really bizarre. Could you give me an example? Thanks in
advance.

Passing it as a parameter to the constructor is one way. this (the instance
pointer) is another. In fact, class member references have to be
initialized in the constructor initialization list (I know of no other way)
and passing as a paramter would be the usuall way. Something like (untested
code)

class Bar {
public:
Bar( Bar& foo ): d( foo ) {}
private:
Bar& d;
};
 
R

Rahul

References and pointers can be created from pre-declared (ie.
incomplete) types. It's not necessary to have the full declaration of
the type in order to create a reference or pointer of that type. That
is, for example, this is valid:

class A; // Incomplete type

void foo(const A&); // Ok

In your example "Bar" has implicitly been pre-declared, and thus it's
ok to create a reference of pointer to it, even inside Bar's declaration.

Then how does a static member object work? The type is incomplete even
for that isn't it?
 
S

Salt_Peter

Hi,
There is a question about nonstatic member. C++ primer says: A
nonstatic member is restricted to being declared as a pointer or
reference to an object of its class. It only gives an example of
pointer *b.

class Bar {
public:

private:
static Bar a; // OK
Bar *b; // OK
Bar c; // error

My question is how a nonstatic member is declared as a reference to an
object of its class. Because a reference is legal only after the
original variable has been declared, where is the original object? I
feel it is really bizarre. Could you give me an example? Thanks in
advance.

private variable

the original object, in a special case like this one, would have to
refer to itself, which would then basicly mean that such a class could
not have a static member since the static member has no 'this'.
Its a special case, don't dissmiss references. They solve many, many
problems.

[10.7] Should you use the this pointer in the constructor?
http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.7

#include <iostream>

class A
{
const A& r_a;
public:
A() : r_a(*this) { }
A(const A& copy) : r_a(copy) { }
A& operator=(const A& rhv); // disabled
A const& get_r() const { return r_a; }
};

void foo(const A& r)
{
std::cout << "&r = " << &r;
std::cout << "\tr.r_a = " << &r.get_r();
std::cout << std::endl;
}

int main()
{
A a;
foo(a);
A another = a; // is NOT an assignment
foo(another);
}

/*
&r = 0x7fff0f2e1930 r.r_a = 0x7fff0f2e1930
&r = 0x7fff0f2e1920 r.r_a = 0x7fff0f2e1930
*/
 
J

James Kanze

The correct terminology is "incomplete type". A class type is
known as soon as it is declared, i.e. immediately after the name
of the class in either a declaration or a definition. The class
type is only complete after the final closing } of the
definition.
. It's not necessary to have the full declaration of

Yes and no. I think that Rahul's problem was more along the
lines of:

class Foo
{
Foo& myFoo ;
} ;

According to the standard, myFoo, here, is a definition (not a
declaration), so one would expect it to be initialized with an
object. Which isn't possible at this point in the program,
because the type Foo is still incomplete, and you cannot have
objects with incomplete types.

The reason, of course, is that the definition of myFoo is
actually a definition of an unspecified number of instances of
the reference; each instance only comes into being when the
constructor of Foo is called. At that point, Foo must be
complete (and the reference must have an initializer, in the
initialization list), or the code is ill formed. (Note that if
the definition of the constructor is given within the class
body, it is processed as if it were immediately following the
complete definition of the class, so even something like the
following is legal:

class Foo
{
public:
Foo() : myFoo( *this ) { }
Foo( Foo& parent ) : myFoo( parent ) {}

Foo& myFoo ;
}

(Note that if the class contains a reference to itself, the only
possible initialization for the first instance is to itself.
Class instances are created one after the other, there are no
null references, and the reference must refer to an "existing"
object.)
Then how does a static member object work? The type is
incomplete even for that isn't it?

A declaration of a non-static data member in a class is a
definition, and requires a complete type. A declaration of a
static data member is not a definition, and so does not require
a complete type (although if the static data member is used, you
must provide a definition somewhere, and the type must be
complete when you provide that definition).

Note the different lifetimes (and storage durations) associated
with static and non-static members. A non-static member has the
same lifetime and storage duration as the containing instance,
and is only initialized (and only requires a complete type) when
the containing instance is initialized. A static member has
static lifetime and storage duration, and is initialized during
static initialization, very much as if it were a variable
declared at namespace scope.
 
J

James Kanze

fl wrote:
Passing it as a parameter to the constructor is one way. this
(the instance pointer) is another. In fact, class member
references have to be initialized in the constructor
initialization list (I know of no other way) and passing as a
paramter would be the usuall way. Something like (untested
code)
class Bar {
public:
Bar( Bar& foo ): d( foo ) {}
private:
Bar& d;
};

Note that if that's the only constructor, there's no way to
create an instance of the class, because in order to create an
instance, you have to have an instance. (Note too that your
constructor is a copy constructor. I'm not sure if this is
intentional or not---it doesn't have the classical copy
semantics, but on the other hand, I can't imagine any other
reasonable approach if you don't want to have to test for null
pointers, etc.)

About the only case I can imagine where a reference to the class
itself would make sense if if you provide a default constructor
which initializes it to *this. Given the usual way people
understand things, I rather suspect that in such cases, most of
the time, using pointers would result in more understandable
code. But that may just be me.
 
F

fl

Hi,
There is a question about nonstatic member. C++ primer says: A
nonstatic member is restricted to being declared as a pointer or
reference to an object of its class. It only gives an example of
pointer *b.
class Bar {
public:
private:
static Bar a;      // OK
Bar *b;              // OK
Bar c;               // error
My question is how a nonstatic member is declared as a reference to an
object of its class. Because a reference is legal only after the
original variable has been declared, where is the original object? I
feel it is really bizarre. Could you give me an example? Thanks in
advance.
private variable

the original object, in a special case like this one, would have to
refer to itself, which would then basicly mean that such a class could
not have a static member since the static member has no 'this'.
Its a special case, don't dissmiss references. They solve many, many
problems.

[10.7] Should you use the this pointer in the constructor?http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.7

#include <iostream>

class A
{
  const A& r_a;
public:
  A() : r_a(*this) { }
  A(const A& copy) : r_a(copy) { }
  A& operator=(const A& rhv); // disabled
  A const& get_r() const { return r_a; }

};

void foo(const A& r)
{
  std::cout << "&r = " << &r;
  std::cout << "\tr.r_a = " << &r.get_r();
  std::cout << std::endl;

}

int main()
{
  A a;
  foo(a);
  A another = a; // is NOT an assignment
  foo(another);

}

/*
&r = 0x7fff0f2e1930     r.r_a = 0x7fff0f2e1930
&r = 0x7fff0f2e1920     r.r_a = 0x7fff0f2e1930
*/- Masquer le texte des messages précédents -

- Afficher le texte des messages précédents -

Hi,
I find the modified code,see below, has the same output as yours.
Why the overload:
A another = a; // is NOT an assignment
does not take effect? Thank you very much.





---------------------
#include <iostream>


class A
{
const A& r_a;
public:
A() : r_a(*this) { }
// A(const A& copy) : r_a(copy) { }
// A& operator=(const A& rhv); // disabled
A const& get_r() const { return r_a; }



};


void foo(const A& r)
{
std::cout << "&r = " << &r;
std::cout << "\tr.r_a = " << &r.get_r();
std::cout << std::endl;


}


int main()
{
A a;
foo(a);
A another; // = a; // is NOT an assignment
foo(another);


}
 
J

Jim Langston

James said:
Note that if that's the only constructor, there's no way to
create an instance of the class, because in order to create an
instance, you have to have an instance. (Note too that your
constructor is a copy constructor. I'm not sure if this is
intentional or not---it doesn't have the classical copy
semantics, but on the other hand, I can't imagine any other
reasonable approach if you don't want to have to test for null
pointers, etc.)

About the only case I can imagine where a reference to the class
itself would make sense if if you provide a default constructor
which initializes it to *this. Given the usual way people
understand things, I rather suspect that in such cases, most of
the time, using pointers would result in more understandable
code. But that may just be me.

Yes, you are right. Although this compiles:

class Foo
{
public:
Foo( Foo& foo ): Ref( foo ) {}
Foo(): Ref( *this ) {}
private:
Foo& Ref;
Foo& operator=( Foo& foo ) {}
};

main()
{
Foo foo;
Foo bar( foo );
}

I could think of someone attempting to do something like this for a linked
list with the first declaration being the head, but I think the destructer
would cause problems as you can't reseat a reference. It could be done, but
probably shouldn't.
 
J

James Kanze

[...]
Yes, you are right. Although this compiles:
class Foo
{
public:
Foo( Foo& foo ): Ref( foo ) {}
Foo(): Ref( *this ) {}
private:
Foo& Ref;
Foo& operator=( Foo& foo ) {}
};
main()
{
Foo foo;
Foo bar( foo );
}

As it should. (And BTW: you don't need the private operator=,
since the compiler won't generate one if the class contains a
reference member.)
I could think of someone attempting to do something like this
for a linked list with the first declaration being the head,
but I think the destructer would cause problems as you can't
reseat a reference. It could be done, but probably shouldn't.

It can't be used for a dynamic structure, that's for sure. On
the other hand, I can imagine it being used for a static tree,
although even then... Maybe it's just me, but when I'm
navigating through a tree, it feels strange to use references,
and not pointers, even if the tree is actually constructed by
the compiler, and you never need to reseat the references.
Also, of course, I'd generally prefer a nul pointer when there
is no corresponding entry (e.g. the parent of the root), rather
than a reference to the object itself.
 
F

fl

Hi,
There is a question about nonstatic member. C++ primer says: A
nonstatic member is restricted to being declared as a pointer or
reference to an object of its class. It only gives an example of
pointer *b.
class Bar {
public:
private:
static Bar a;      // OK
Bar *b;              // OK
Bar c;               // error
My question is how a nonstatic member is declared as a reference to an
object of its class. Because a reference is legal only after the
original variable has been declared, where is the original object? I
feel it is really bizarre. Could you give me an example? Thanks in
advance.
private variable

the original object, in a special case like this one, would have to
refer to itself, which would then basicly mean that such a class could
not have a static member since the static member has no 'this'.
Its a special case, don't dissmiss references. They solve many, many
problems.

[10.7] Should you use the this pointer in the constructor?http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.7

#include <iostream>

class A
{
  const A& r_a;
public:
  A() : r_a(*this) { }
  A(const A& copy) : r_a(copy) { }
  A& operator=(const A& rhv); // disabled
  A const& get_r() const { return r_a; }

};

void foo(const A& r)
{
  std::cout << "&r = " << &r;
  std::cout << "\tr.r_a = " << &r.get_r();
  std::cout << std::endl;

}

int main()
{
  A a;
  foo(a);
  A another = a; // is NOT an assignment
  foo(another);

}

/*
&r = 0x7fff0f2e1930     r.r_a = 0x7fff0f2e1930
&r = 0x7fff0f2e1920     r.r_a = 0x7fff0f2e1930
*/- Masquer le texte des messages précédents -

- Afficher le texte des messages précédents -

Sorry, my previous response is not right, i.e. Your's

A another = a; // is NOT an assignment

is right.
My question now is: why there is no effect when I comment out:
// A(const A& copy) : r_a(copy) { }
// A& operator=(const A& rhv); // disabled

Maybe the system does the copy in a special initializer fashion?
I know now the object of "A" class is an address, which points to
itself. That is from the following two lines. Right?
const A& r_a;
public:
A() : r_a(*this) { }

---------------
Then, what's the meaning of "another" after "another=a"?
I am not even clear:

A(const A& copy) : r_a(copy) { }


Thanks.
 
D

Daniel T.

fl said:
There is a question about nonstatic member. C++ primer says: A
nonstatic member is restricted to being declared as a pointer or
reference to an object of its class. It only gives an example of
pointer *b.

class Bar {
public:

private:
static Bar a; // OK
Bar *b; // OK
Bar c; // error

My question is how a nonstatic member is declared as a reference to an
object of its class. Because a reference is legal only after the
original variable has been declared, where is the original object? I
feel it is really bizarre. Could you give me an example? Thanks in
advance.

I have yet to see why one should have a non-static reference in a class
in any case, no matter what it refers to.
 
S

Salt_Peter

the original object, in a special case like this one, would have to
refer to itself, which would then basicly mean that such a class could
not have a static member since the static member has no 'this'.
Its a special case, don't dissmiss references. They solve many, many
problems.
[10.7] Should you use the this pointer in the constructor?http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.7
#include <iostream>
class A
{
const A& r_a;
public:
A() : r_a(*this) { }
A(const A& copy) : r_a(copy) { }
A& operator=(const A& rhv); // disabled
A const& get_r() const { return r_a; }

void foo(const A& r)
{
std::cout << "&r = " << &r;
std::cout << "\tr.r_a = " << &r.get_r();
std::cout << std::endl;

int main()
{
A a;
foo(a);
A another = a; // is NOT an assignment
foo(another);

/*
&r = 0x7fff0f2e1930 r.r_a = 0x7fff0f2e1930
&r = 0x7fff0f2e1920 r.r_a = 0x7fff0f2e1930
*/- Masquer le texte des messages précédents -
- Afficher le texte des messages précédents -

Sorry, my previous response is not right, i.e. Your's

A another = a; // is NOT an assignment

is right.
My question now is: why there is no effect when I comment out:
// A(const A& copy) : r_a(copy) { }
// A& operator=(const A& rhv); // disabled

the compiler generates the copy ctor if you don't. it probably does
the exact same as the one commented out.
I prefer declaring it in cases i want to diagnose problems and assert
theories.

A(const A& copy) : r_a(copy) { std::cout << "copy A"; }

is nice to have when observing and troubleshooting.

Maybe the system does the copy in a special initializer fashion?

not at all. Its a member-wise copy, nothing special.

Its the same with something like
struct K
{
int n;
double d;
char c;
};

You can initialize an instance of K and you can copy it because the
compiler generates a copy ctor for you. It also generates a defult
ctor and an assignment operator (if needed).
I know now the object of "A" class is an address, which points to
itself. That is from the following two lines. Right?
const A& r_a;
public:
A() : r_a(*this) { }

---------------
Then, what's the meaning of "another" after "another=a"?
I am not even clear:

A(const A& copy) : r_a(copy) { }

Thanks.

instance 'another' is a psuedo-copy of a. The difference is that
another's member reference doesn't refer to another.
This isn't something you need not worry about, you'll not find such a
strategy in code out there.
You do need to understand ctor, copy ctor and init list.
 

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

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,007
Latest member
obedient dusk

Latest Threads

Top