size of class same as base class if no new data members?


G

guy.tristram

Can I assume that if I have:

class A
{
/* a few built in types */
};

class B : public A
{
private:
//prevent copy and assignment
B( B const & );
operator=( B const & );
};

instances of class A will be the same size as instances of class B?
More particularly, if I have:

std::vector< A > v(2);
B *b = static_cast< B * >( &v[0] );
++b;

will b point to the second element of v? Does the standard offer any
guarantees? My motivation is that I want to be able to grow a vector
of As, but prevent clients from copying them thereafter. I realize
that I am then using As as though they were Bs and I should perhaps
inherit the other way around, making the copy constructor and
assignment operator protected in the client version, then re-
publicizing them in the internal version, but that would mean
explicitly implementing them.

Guy
 
Ad

Advertisements

V

Victor Bazarov

Can I assume that if I have:

class A
{
/* a few built in types */

You mean, there are data members here? 'cause your class looks like it
has no data members at all...
};

class B : public A
{
private:
//prevent copy and assignment
B( B const & );
operator=( B const & );
};

instances of class A will be the same size as instances of class B?

Since 'B' adds no data and no virtual functions or virtual base classes,
then yes, most likely.
More particularly, if I have:

std::vector< A > v(2);
B *b = static_cast< B * >( &v[0] );
++b;

will b point to the second element of v?

No. The code has undefined behaviour. You can't use 'static_cast' that
way. The object at the address &v[0] is of type 'A', and it is not a
subobject of some other object of type 'B'.
> Does the standard offer any
guarantees?

Of course not.
> My motivation is that I want to be able to grow a vector
of As, but prevent clients from copying them thereafter.

It would seem that you're solving a wrong problem. If you care to
explain what you're trying to accomplish, folks here might have
suggestions on what you should do to get it.
> I realize
that I am then using As as though they were Bs and I should perhaps
inherit the other way around, making the copy constructor and
assignment operator protected in the client version, then re-
publicizing them in the internal version, but that would mean
explicitly implementing them.

Uh... Don't know.

V
 
J

James Kanze

Can I assume that if I have:
class A
{
/* a few built in types */
};
class B : public A
{
private:
//prevent copy and assignment
B( B const & );
operator=( B const & );
};
instances of class A will be the same size as instances of
class B?

No. All you can be sure of is that sizeof B is greater or equal
to sizeof A.
More particularly, if I have:
std::vector< A > v(2);
B *b = static_cast< B * >( &v[0] );
++b;
will b point to the second element of v?

Maybe. It's undefined behavior; anything could happen.
Does the standard offer any guarantees?

It's explicitly undefined behavior.
 
G

guy.tristram

He meant that showing a few members of built-in types wouldn't be
practical in a Usenet posting:

    class A
    {
        int i;
        double d;
    };

See? Way too impractical. :)

It seems that my attempt to avoid adding noise to the example
backfired :)
 
G

guy.tristram

You mean, there are data members here?  'cause your class looks like it
has no data members at all...

Yes. Sorry if that wasn't obvious.
It would seem that you're solving a wrong problem.  If you care to
explain what you're trying to accomplish, folks here might have
suggestions on what you should do to get it.

I have a std::vector of nodes which represent a tree. Each node
contains the distance to the next sibling (equal to the number of
descendents of that node plus one). I have two iterator classes. One
iterates through the children of a node, the other through all
descendents of a node. The address of the first child of a node is the
address of that node plus one. This works fine as long as the nodes
are in the vector, but I need to prevent client code from copying
nodes, whilst the code assembling the vector needs to work with
copyable nodes. I wanted to do this without jumping through too many
hoops, but it seems my first attempt took an illegal shortcut.

I think I can make it legal by having the copyable node type derive
from the non-copyable node which the client sees. The iterators will
have to contain pointers to the copyable node type so that they will
increment correctly, which may cause order-of-declaration headaches.
It also means that I have to implement the copy constructor
explicitly.

I hope I have explained this more clearly than in my original post.

Guy
 
Ad

Advertisements

V

Victor Bazarov

Yes. Sorry if that wasn't obvious.


I have a std::vector of nodes which represent a tree. Each node
contains the distance to the next sibling (equal to the number of
descendents of that node plus one). I have two iterator classes. One
iterates through the children of a node, the other through all
descendents of a node. The address of the first child of a node is the
address of that node plus one. This works fine as long as the nodes
are in the vector, but I need to prevent client code from copying
nodes, whilst the code assembling the vector needs to work with
copyable nodes. I wanted to do this without jumping through too many
hoops, but it seems my first attempt took an illegal shortcut.

I think I can make it legal by having the copyable node type derive
from the non-copyable node which the client sees. The iterators will
have to contain pointers to the copyable node type so that they will
increment correctly, which may cause order-of-declaration headaches.
It also means that I have to implement the copy constructor
explicitly.

I hope I have explained this more clearly than in my original post.

OK, what if you derive, as you did, but instead of using static_cast you
simply construct 'B' from an 'A':

class B : public A
{
public:
B(A const& a) : A(a) {}
};

Would that work for you?

V
 
Ad

Advertisements

G

guy.tristram

OK, what if you derive, as you did, but instead of using static_cast you
simply construct 'B' from an 'A':

    class B : public A
    {
    public:
       B(A const& a) : A(a) {}
    };

Would that work for you?

Unfortunately no. A copy is no good, because the object's address is
important.

I have fixed this now I think. I now have three classes:
NodeData - this is seperated out so I can use its compiler generated
copy contructor and assignment.
Node (derived from NodeData) - this is the class the client code
sees. It's constructors are protected and implemented to call
NodeData's ones.
CopyableNode (derived from Node) - a version which can be used in a
std::vector

Now the same cast as before is safe because there are can be no Nodes
instanciated, only CopyableNodes.

inline Node::iterator::iterator( Node const *p, int offset )
: p( static_cast< CopyableNode const * >( p ) + offset ) {}

where Node::iterator's p is a CopyableNode *, so pointer arithmetic in
e.g.

inline Node::child_iterator &Node::child_iterator::eek:perator++()
{ p += p->next_sibling; return *this; }

is safe


I nearly missed a trick because I was adding offset to p in Node::begin
(), Node::end() etc. which would have done pointer arithmetic with the
wrong type.

Anyway, it seems to work and I don't think there's any undefined
behaviour now. Thanks for your help.

Guy
 

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