473,444 Members | 1,973 Online
Bytes | Software Development & Data Engineering Community
Create Post

Home Posts Topics Members FAQ

Interview questions

cj
Dear friends, I have one more questions for everyone in the newsgroup:

I am preparing for an interview on UNIX/C++. Could you please identify some
of the most important questions which might be asked, so that I could best
prepare for it?

Thank you,
C++J
Jul 22 '05
71 5817
JKop wrote:
Opps, that wasn't my intention, this was my intention:
int main(void)
{
int monkeys[7] = { 3, 4 ,3, 2 ,2 ,34, 23};

std::cout << reinterpret_cast<char&>(monkeys[5]);
}



That's dangerous, you are passing to ostream::operator<<() a char & to a
temporary.
What you probably meant to do is:

#include <iostream>
int main(void)
{
int monkeys[7] = { 3, 4 ,3, 2 ,2 ,34, 23};

std::cout << static_cast<char>(monkeys[5]);
}

Also reinterpret_cast is the *last* of castings you should use, and
except of that, always try to avoid using castings at all.


Regards,

Ioannis Vranos
Jul 22 '05 #51
Ioannis Vranos posted:
JKop wrote:
Is reinterpret_cast stupid, by which I mean does it do any processing
at all? For example, take the following:

unsigned char jk;

reinterpret_cast<unsigned long&>(jk) = 4000000000UL;

Opps!! static_cast was what I was after:
unsigned char jk;

static_cast<unsigned long&>(jk) = 4000000000UL;
Here's an excerpt from http://msdn.microsoft.com/library/default.asp?
url=/library/en-us/vccelng/htm/express_74.asp :

This behavior also applies to types other than class types. For instance,
static_cast can be used to convert from an int to a char. However, the
resulting char may not have enough bits to hold the entire int value. Again,
it is left to the programmer to ensure that the results of a static_cast
conversion are safe.

union {

double double_data;
int int_data;
char char_data;
unsigned long unsigned_long_data;
void* void_pointer_data;
float* float_pointer_data;

} monkey;

//Now some funky code:

double recpoo;

static_cast<float*&>(recpoo) = &some_global_float;

static_cast<unsigned long&>(recpoo) = 4000000000UL;

static_cast<char&>(recpoo) = 'g';
-JKop
Jul 22 '05 #52
JKop wrote:
Opps!! static_cast was what I was after:
unsigned char jk;

static_cast<unsigned long&>(jk) = 4000000000UL;



That doesn't compile. However as I said in another message, casts are to
be used on the assigned value, not the object that gets that value.


Regards,

Ioannis Vranos
Jul 22 '05 #53
Ioannis Vranos wrote:
JKop wrote:
Is reinterpret_cast stupid, by which I mean does it do any processing
at all? For example, take the following:

unsigned char jk;

reinterpret_cast<unsigned long&>(jk) = 4000000000UL;


Reinterpret_cast performs a value conversion. It doesn't modify anything
on the implementation of jk. So the above has essentially no effect. It
is as if you had written


unsigned char jk;

reinterpret_cast<unsigned long&>(jk);

jk=4000000000UL;


Regards,

Ioannis Vranos
Jul 22 '05 #54
JKop posted:
This behavior also applies to types other than class types. For
instance, static_cast can be used to convert from an int to a char.
However, the resulting char may not have enough bits to hold the entire
int value. Again, it is left to the programmer to ensure that the
results of a static_cast conversion are safe.


This excerpt seems to be bullshit. Try running the following on your system.
If the above was true, then the end output should be all 255, assuming that
your system is 8-Bit char and 32-Bit long.
#include <iostream>

int main(void)
{
unsigned char jk[4] = { 0, 0, 0, 0 };

std::cout << "jk[0] == " << (int)jk[0]
<< "\r\njk[1] == " << (int)jk[1]
<< "\r\njk[2] == " << (int)jk[2]
<< "\r\njk[3] == " << (int)jk[3]
<< std::endl;

std::system("PAUSE");

static_cast<unsigned long>(jk[0]) = 0xFFFFFFFF;

std::cout << "jk[0] == " << (int)jk[0]
<< "\r\njk[1] == " << (int)jk[1]
<< "\r\njk[2] == " << (int)jk[2]
<< "\r\njk[3] == " << (int)jk[3]
<< std::endl;

std::system("PAUSE");
}
static_cast isn't as special as I thought. I thought it would've been able
to achieve what unions do. Ah well!
-JKop
Jul 22 '05 #55
Siemel Naran wrote:
I think [that]
the virtual table is implemented as an array of pointers to functions.
A jump table.
It works well whenever a pointer to a function
of any signature has the same size, which is normally the case.
If you have a class as follows.
Note what follows is a typical implementation,
not what the standard mandates.

class Foo { public: virtual ~Foo(void);
virtual int f(int, int);
virtual double g(int) const;
};

then the virtual table is an array of length 3.
Each element in the array is a function pointer,
but each function pointer is a different signature!
Sure, the compiler can do that, but we can't! cat main.cc class Foo {
private:
int F;
public:
virtual ~Foo(void) { }
virtual int f(int i, int j) {
int t = F;
F = i + j;
return t; }
virtual double g(int k) const { return F + k; }
};

int funny(Foo& foo) {
return foo.f(13, 23);
}

int main(int argc, char* argv[]) {
Foo foo;
return funny(foo);
}
g++ -Wall -ansi -pedantic -O2 -S main.cc
cat main.s

Jul 22 '05 #56
Mike Wahler wrote:
Yes, the standard does guarantee that
compliant code is portable to a compliant implementation.
Please cite and quote the passage in the standard
that "guarantees" this.
Of course,
compliant implementations do not exist for all platforms.


In fact, no compliant implementations exist for any platform.
The claim is vacuous.

The license that came with my GNU C++ compiler
includes the following disclaimer:

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

When you installed your compiler,
you were obliged to accept "similar terms and conditions".
Compliance with ANSI/ISO C++ standards is voluntary.
Programmers have no legal recourse against compiler developers
if their compliant programs will not port.
Jul 22 '05 #57
"Siemel Naran" <Si*********@REMOVE.att.net> wrote in message news:<jr********************@bgtnsc04-news.ops.worldnet.att.net>...
"pembed2003" <pe********@yahoo.com> wrote in message
possible function definition. The lookup (not sure how the actual
virtual table is implemented but if it's something like a binary tree
or hash table then...) thus takes appr. the same amount of time.


I think the virtual table is implemented as an array of pointers to
function. It works well whenever a pointer to a function of any signature
has the same size, which is normally the case. If you have a class as
follows.

Note what follows is a typical implementation, not what the standard
mandates.

class Foo {
virtual ~Foo();
virtual int f(int, int);
virtual double g(int) const;
};

then the virtual table is an array of length 3. Each element in the array
is a function pointer, but each function pointer is a different signature!
Sure, the compiler can do that, but we can't!


Sure we can. Here's how you might do something very similar in C. I haven't
tried compiling it, but I've done similar things in the past. (For example,
for anyone masochistic enough to do COM programming in C, the code usually
looks pretty similar to this once you strip away all the macros.)

/*
* Declaration of Foo in foo.h
*/
struct Foo_VTable;

typedef struct tagFoo {
Foo_VTable* _vptr;
} Foo;

struct Foo_VTable {
void (*dtor)(Foo* _this);
int (*f)(Foo* _this, int, int);
double (*g)(Foo const* _this, int);
};

void Foo_ctor(Foo* _this);
void Foo_dtor(Foo* _this);
int Foo_f(Foo* _this, int, int);
double Foo_g(Foo const* _this, int);

/*
* Implementation of Foo in foo.c.
*/
struct Foo_VTable const g_Foo_vtable = {
&Foo_dtor,
&Foo_f,
&Foo_g
};

void Foo_ctor(Foo* _this)
{
_this->_vfptr = &g_Foo_vtable;
}

/* etc. for other member functions */

/*
* The following is essentially equivalent to what
* in C++ would be written:
* Foo foo;
* foo.f(0, 0);
* foo.g(0);
*/
Foo foo;
Foo_ctor(&foo);
foo._vfptr->f(&foo, 0, 0);
foo._vfptr->g(&foo, 0);
foo._vfptr->dtor();

/*
* The following is essentially equivalent to what
* in C++ would be written:
* Foo* foo = new Foo();
* foo->f(0, 0);
* foo->g(0);
* delete foo;
*/
Foo* foo = malloc(sizeof(Foo));
Foo_ctor(foo);
foo->_vfptr->f(foo, 0, 0);
foo->_vfptr->g(foo, 0);
foo->_vfptr->dtor();
free(foo);
Jul 22 '05 #58
Niklas Borson wrote:
Sure we can.
Here's how you might do something very similar in C.
I haven't tried compiling it,
but I've done similar things in the past. (For example,
for anyone masochistic enough to do COM programming in C,
the code usually looks pretty similar to this
once you strip away all the macros.)

// Declaration of Foo in foo.h

struct Foo_VTable;

typedef struct tagFoo {
Foo_VTable* _vptr;
Should be

const void* _vptr;
} Foo;

struct Foo_VTable {
void (*dtor)(Foo* _this);
Should be

void (*dtor)(const Foo*);

You need to be able to destroy const objects
as well as variable objects with the same destructor!
int (*f)(Foo* _this, int, int);
double (*g)(Foo const* _this, int);
};

void Foo_ctor(Foo* _this);
void Foo_dtor(Foo* _this);
Should be

void Foo_dtor(const Foo*);
int Foo_f(Foo* _this, int, int);
double Foo_g(Foo const* _this, int);
// Implementation of Foo in foo.c.
#include "foo.h"

// Actually, the struct Foo_VTable definition
// belongs here and *not* in the public header file.
struct Foo_VTable const g_Foo_vtable = {
&Foo_dtor,
&Foo_f,
&Foo_g
};

void Foo_ctor(Foo* _this) {

_this->_vfptr = &g_Foo_vtable;
}

// etc. for other member functions
// The following is essentially equivalent to what
// what in C++ would be written:
// Foo foo;
// foo.f(0, 0);
// foo.g(0);

Foo foo;
Foo_ctor(&foo);
foo._vfptr->f(&foo, 0, 0);
foo._vfptr->g(&foo, 0);
foo._vfptr->dtor();
Should be

foo._vfptr->dtor(foo);


// The following is essentially equivalent to what
// in C++ would be written:
// Foo* foo = new Foo();
// foo->f(0, 0);
// foo->g(0);
// delete foo;

Foo* foo = malloc(sizeof(Foo));
Foo_ctor(foo);
foo->_vfptr->f(foo, 0, 0);
foo->_vfptr->g(foo, 0);
foo->_vfptr->dtor();
Should be

foo->_vfptr->dtor(foo);
free(foo);


Now suppose that you want to *derive* Bar from Foo

// interface
#include "foo.h"

typedef struct Bar {
Foo foo;
} Bar;

Bar Bar_ctor(void);
void Bar_dtor(const Bar*);
int Bar_f(Bar*, int, int);
double Bar_g(Foo const* _this, int);
char* Bar_hello(const Bar*);

// implementation
#include "bar.h"

struct Bar_VTable {
void (*dtor)(const Bar*);
int (*f)(Bar*, int, int);
double (*g)(Bar const*, int);
char* hello(const Bar*);
} Bar_VTable;

const Bar_VTable g_Foo_vtable = {
Bar_dtor,
Bar_f,
Bar_g,
Bar_hello
};

Bar Bar_ctor(void) {
Bar bar;
bar.foo._vptr = (const void*)(&g_Foo_vtable);
return Bar;
}

// etc.

// usage
Bar bar = Bar_ctor();
Foo* pBar = (Foo*)(&bar);
((const struct Foo_VTable*)(pBar->foo._vfptr))->f(pBar, 0, 0);
((const struct Foo_VTable*)(pBar->foo._vfptr))->g(pBar, 0);
((const struct Foo_VTable*)(pBar->foo._vfptr))->dtor(pBar);
Jul 22 '05 #59

"Ioannis Vranos" <iv*@guesswh.at.grad.com> skrev i en meddelelse
news:cb***********@ulysses.noc.ntua.gr...
Ioannis Vranos wrote:
E. Robert Tisdale wrote:
How much more time it takes for the implementation to find and invoke
base999999::something()
in comparison to base78::something()?

It depends upon the implementation (compiler).
In the typical implementation, it takes no more time.
The C++ computer programming language standard
does *not* specify implementations, performance or efficiency.



Wrong. Next please. :-)

But I forgot to give you a reference. "The C++ Programming Language" 3rd
Edition or Special Edition, page 324.


Regards,

Ioannis Vranos


Well.... however brilliant "The C++ Programming Language" might be, it can
not answer your question.
You better consult the C++ standard for for answers to questions of that
caliber.
/Peter
Jul 22 '05 #60
"E. Robert Tisdale" <E.**************@jpl.nasa.gov> wrote in message news:<cb**********@nntp1.jpl.nasa.gov>...
Niklas Borson wrote:
Sure we can.
Here's how you might do something very similar in C.
I haven't tried compiling it,
but I've done similar things in the past. (For example,
for anyone masochistic enough to do COM programming in C,
the code usually looks pretty similar to this
once you strip away all the macros.)

// Declaration of Foo in foo.h

struct Foo_VTable;

typedef struct tagFoo {
Foo_VTable* _vptr;
Should be

const void* _vptr;


No, but you're right about the const. It should be:

Foo_VTable const* _vptr;
} Foo;

struct Foo_VTable {
void (*dtor)(Foo* _this);


Should be

void (*dtor)(const Foo*);

You need to be able to destroy const objects
as well as variable objects with the same destructor!


Yes, if you want to following the example of C++, but
if course if you're reinventing the wheel you have the
option of changing the rules. :-)
int (*f)(Foo* _this, int, int);
double (*g)(Foo const* _this, int);
};

void Foo_ctor(Foo* _this);
void Foo_dtor(Foo* _this);


Should be

void Foo_dtor(const Foo*);


Yes. Same as above.
int Foo_f(Foo* _this, int, int);
double Foo_g(Foo const* _this, int);
// Implementation of Foo in foo.c.


#include "foo.h"

// Actually, the struct Foo_VTable definition
// belongs here and *not* in the public header file.


No, because the user of the class needs to know the layout
of the vtable structure in order to call pseudo-virtual
functions (see example below).
struct Foo_VTable const g_Foo_vtable = {
&Foo_dtor,
&Foo_f,
&Foo_g
};

void Foo_ctor(Foo* _this) {

_this->_vfptr = &g_Foo_vtable;
}

// etc. for other member functions
// The following is essentially equivalent to what
// what in C++ would be written:
// Foo foo;
// foo.f(0, 0);
// foo.g(0);

Foo foo;
Foo_ctor(&foo);
foo._vfptr->f(&foo, 0, 0);
foo._vfptr->g(&foo, 0);
foo._vfptr->dtor();


Should be

foo._vfptr->dtor(foo);


Doh! Like I said, I didn't try to compile it. But this example
shows clearly why _vfptr can't just be a const void*, and why
the user of the class needs access to the definition of
Foo_VTable.
// The following is essentially equivalent to what
// in C++ would be written:
// Foo* foo = new Foo();
// foo->f(0, 0);
// foo->g(0);
// delete foo;

Foo* foo = malloc(sizeof(Foo));
Foo_ctor(foo);
foo->_vfptr->f(foo, 0, 0);
foo->_vfptr->g(foo, 0);
foo->_vfptr->dtor();


Should be

foo->_vfptr->dtor(foo);


Yes, same as above.
free(foo);


Now suppose that you want to *derive* Bar from Foo


Then Bar would have to have its own Bar_VTable structure
definition whould would have the same members as Foo_VTable
plus possibly some additional members. It too would have to
be public, and each isntance of Bar would point to a static
const instance of Bar_VTable.
Jul 22 '05 #61
Niklas Borson wrote:
E. Robert Tisdale wrote:
Niklas Borson wrote:
Sure we can.
Here's how you might do something very similar in C.
I haven't tried compiling it,
but I've done similar things in the past. (For example,
for anyone masochistic enough to do COM programming in C,
the code usually looks pretty similar to this
once you strip away all the macros.)

// Declaration of Foo in foo.h

struct Foo_VTable;

typedef struct tagFoo {
Foo_VTable* _vptr;
Should be

const void* _vptr;


No, but you're right about the const. It should be:

Foo_VTable const* _vptr;

} Foo;

struct Foo_VTable {
void (*dtor)(Foo* _this);


Should be

void (*dtor)(const Foo*);

You need to be able to destroy const objects
as well as variable objects with the same destructor!

Yes, if you want to following the example of C++ but,
of course, if you're reinventing the wheel,
you have the option of changing the rules. :-)


But you don't have the option of failing to destroy const objects.
They may contain pointers to memory allocated dynamically
and you will need to free that memory unless you want memory leaks.
int (*f)(Foo* _this, int, int);
double (*g)(Foo const* _this, int);
};

void Foo_ctor(Foo* _this);
void Foo_dtor(Foo* _this);


Should be

void Foo_dtor(const Foo*);


Yes. Same as above.


No. Same as above.
int Foo_f(Foo* _this, int, int);
double Foo_g(Foo const* _this, int);
// Implementation of Foo in foo.c.


#include "foo.h"

// Actually, the struct Foo_VTable definition
// belongs here and *not* in the public header file.


No, because the user of the class needs to know the layout
of the vtable structure in order to call pseudo-virtual
functions (see example below).


No. The user should *not* call the functions out of the vtable directly
but implement *virtual* functions in foo.c or bar.c that do so.
struct Foo_VTable const g_Foo_vtable = {
&Foo_dtor,
&Foo_f,
&Foo_g
};

void Foo_ctor(Foo* _this) {

_this->_vfptr = &g_Foo_vtable;
}

// etc. for other member functions
// The following is essentially equivalent to what
// what in C++ would be written:
// Foo foo;
// foo.f(0, 0);
// foo.g(0);

Foo foo;
Foo_ctor(&foo);
foo._vfptr->f(&foo, 0, 0);
foo._vfptr->g(&foo, 0);
foo._vfptr->dtor();


Should be

foo._vfptr->dtor(foo);


Doh! Like I said, I didn't try to compile it. But this example
shows clearly why _vfptr can't just be a const void*, and why
the user of the class needs access to the definition of
Foo_VTable.


No. See example below.
// The following is essentially equivalent to what
// in C++ would be written:
// Foo* foo = new Foo();
// foo->f(0, 0);
// foo->g(0);
// delete foo;

Foo* foo = malloc(sizeof(Foo));
Foo_ctor(foo);
foo->_vfptr->f(foo, 0, 0);
foo->_vfptr->g(foo, 0);
foo->_vfptr->dtor();


Should be

foo->_vfptr->dtor(foo);


Yes, same as above.
free(foo);


Now suppose that you want to *derive* Bar from Foo


Then Bar would need to have
its own Bar_VTable structure definition
which would have the same members as Foo_VTable
plus possibly some additional members.


Which my example shows:

// implementation
#include "bar.h"

struct Bar_VTable {
void (*dtor)(const Bar*);
int (*f)(Bar*, int, int);
double (*g)(Bar const*, int);
char* hello(const Bar*);
} Bar_VTable;

const Bar_VTable g_Bar_vtable = {
Bar_dtor,
Bar_f,
Bar_g,
Bar_hello
};
It too would have to be public and each instance of Bar
would point to a static const instance of Bar_VTable.


No!
Bar is *derived* from Foo.
An object of type Bar *is* an object of type Foo.
There is no special syntax in C to express this
so you *must* write:

typedef struct Bar {
Foo foo;
// and, possibly, other data members
} Bar;

An object of type Bar *encapsulates* an object of type Foo.
If, insteas, you write

typedef struct Bar {
Foo foo;
const Bar_VTable* _vptr;
// and, possibly, other data members
} Bar;

You cannot pass a pointer to an object of type Bar
to a function of a pointer to an object of type Foo
and expect it to find pointer member _vptr.

The user should *not* call the functions
out of the virtual function table directly.
Instead, the class library developer should provide
*virtual* functions which do this for the user

int Foo_virtual_f(Foo* _this, int i, int j) {
return ((const Foo_VTable*)(_this->_vptr))->f(_this, i, j);
}

for example.
That way, the actual representation of the virtual function table
remains private to the implementation.
Jul 22 '05 #62
"E. Robert Tisdale" <E.**************@jpl.nasa.gov> wrote in message news:<cb**********@nntp1.jpl.nasa.gov>...
Niklas Borson wrote:
E. Robert Tisdale wrote: [snip]
You need to be able to destroy const objects
as well as variable objects with the same destructor!
Yes, if you want to following the example of C++ but,
of course, if you're reinventing the wheel,
you have the option of changing the rules. :-)


But you don't have the option of failing to destroy const objects.
They may contain pointers to memory allocated dynamically
and you will need to free that memory unless you want memory leaks.


I'll go along with that. I was thinking of the argument that
comes up from time to time of whether it should be possible
to delete an object through a pointer-to-const. It is possible,
of course, but some people think it shouldn't be.

// Actually, the struct Foo_VTable definition
// belongs here and *not* in the public header file.


No, because the user of the class needs to know the layout
of the vtable structure in order to call pseudo-virtual
functions (see example below).


No. The user should *not* call the functions out of the vtable
directly but implement *virtual* functions in foo.c or bar.c
that do so.


If I understand correctly, you're saying the users of the
class should call a wrapper function which in turn calls
the actual virtual function through the pointer in the
vtable. Yes, one could do this.

Personally, I don't see the advantage of this extra
function call. IMO, exposing the structure of the vtable
does not violate encapsulation. It doesn't expose the
class's data, for example. It tells you only what virtual
functions the class has -- i.e., its interface.

Moreover, anyone who wants to derive from the class
needs to know the structure of the vtable anyway so
as to provide a compatible vtable for the derived
class.
Now suppose that you want to *derive* Bar from Foo


Then Bar would need to have
its own Bar_VTable structure definition
which would have the same members as Foo_VTable
plus possibly some additional members.


Which my example shows:

// implementation
#include "bar.h"

struct Bar_VTable {
void (*dtor)(const Bar*);
int (*f)(Bar*, int, int);
double (*g)(Bar const*, int);
char* hello(const Bar*);
} Bar_VTable;

const Bar_VTable g_Bar_vtable = {
Bar_dtor,
Bar_f,
Bar_g,
Bar_hello
};


Yes, and note that this means the implementor of Bar needs to
know the structure of Foo_VTable because the members they have
in common have to have the same layout. This to me suggests
that the structure of the vtable is part of the interface of
a class -- at least for derivers of the class, so why not for
users of the class as well. (Of course if you're using C++
the structure of the vtable is compiler-dependant, but it
is still *implied* by the class definition, and is visible to
other C++ code that uses the class.)

As an aside, note that the virtual methods themselves need to
be visible directly (not just through pointers) for a couple
of reasons. First, Bar_dtor should call Foo_dtor.

Second, Bar might want to inherit some virtual methods of Foo.
For example, to inherit f, we'd set the second member of
g_Bar_vtable to Foo_f instead of Bar_f.
It too would have to be public and each instance of Bar
would point to a static const instance of Bar_VTable.


No!
Bar is *derived* from Foo.
An object of type Bar *is* an object of type Foo.
There is no special syntax in C to express this
so you *must* write:

typedef struct Bar {
Foo foo;
// and, possibly, other data members
} Bar;


The above is the layout we'd use if we wanted to follow the
typicall C++ approach. The constructor for Bar would be
implemented something like this:

void Bar_ctor(Bar* bar)
{
// Initialize the foo "base class"; as per C++ rules,
// the virtual function pointer will point to the base
// class vtable during base class initialization.
Foo_ctor(&bar->foo);

// Now change the virtual function pointer to point to
// the "derived" class vtable. This requires that the
// vtables have a compatible layout.
bar->foo->_vptr = &g_Bar_vtable;

// Perform other initialization here.
}

Because of the compatible vtable layouts, and because Foo
is the first member of bar, we can say a Bar "is a" Foo.
Of course, a C compiler doesn't know this so a cast is
requird to convert a Bar* to a Foo*.
An object of type Bar *encapsulates* an object of type Foo.
If, insteas, you write

typedef struct Bar {
Foo foo;
const Bar_VTable* _vptr;
// and, possibly, other data members
} Bar;

You cannot pass a pointer to an object of type Bar
to a function of a pointer to an object of type Foo
and expect it to find pointer member _vptr.
Of course not, and I never suggested using the above
representation.
The user should *not* call the functions
out of the virtual function table directly.
Instead, the class library developer should provide
*virtual* functions which do this for the user

int Foo_virtual_f(Foo* _this, int i, int j) {
return ((const Foo_VTable*)(_this->_vptr))->f(_this, i, j);
}

for example.
That way, the actual representation of the virtual
function table remains private to the implementation.


Well, not exactly private. More like "protected" as
implementors of derived classes still need to know
the vtable layout.

Like I said above, you could this. I see nothing wrong
with providing wrapper functions like the above. But
I don't agree that exposing the structure of a vtable
violates encapsulation. It exposes only the set of
virtual functions a class provides -- which is part
of its interface -- not any of the class's actual
data.
Jul 22 '05 #63
Niklas Borson wrote:
E. Robert Tisdale wrote:
But you don't have the option of failing to destroy const objects.
They may contain pointers to memory allocated dynamically
and you will need to free that memory unless you want memory leaks.
I'll go along with that.


You had me worried.
I was thinking of the argument that comes up from time to time
of whether it should be possible
to delete an object through a pointer-to-const.
It is possible, of course, but some people think it shouldn't be.
The user should *not* call the functions out of the vtable directly
but implement *virtual* functions in foo.c or bar.c that do so.
If I understand correctly, you're saying [that]
the users of the class should call a wrapper function
which in turn calls the actual function
through the pointer in the vtable.
Yes, one could do this.


What I am saying is that this is what your C++ compiler does for you.
A virtual function is actually a wrapper
(that's why it's called a virtual function) that calls
the actual function through the corresponding function pointer
in the virtual function table.
Personally,
I don't see the advantage of this extra function call.
IMO, exposing the structure of the vtable
does not violate encapsulation. It doesn't expose the class's data, for example.
It tells you only what virtual functions the class has --
i.e., its interface.
No!
It is an implementation detail.
Siemel Naran used an array
to represent the virtual function table.
Moreover, anyone who wants to derive from the class
needs to know the structure of the vtable anyway so
as to provide a compatible vtable for the derived class.
That's because the C computer programming language
does *not* support inheritance.

Yes, the application programmer (user) must know the *order*
in which function pointers appear in struct Foo_VTable
but the application programmer does *not* need the definition
of struct Foo_VTable to define struct Bar_VTable.
My example shows:

// implementation
#include "bar.h"

struct Bar_VTable {
void (*dtor)(const Bar*);
int (*f)(Bar*, int, int);
double (*g)(Bar const*, int);
char* hello(const Bar*);
} Bar_VTable;

const Bar_VTable g_Bar_vtable = {
Bar_dtor,
Bar_f,
Bar_g,
Bar_hello
};


Yes, and note that this means [that]
the implementor of Bar needs to know the structure of Foo_VTable


Well, at least the order in which function pointers appear.
because the members they have in common [must] have the same layout.
This to me suggests that the structure of the vtable
is part of the interface of a class --
at least for derivers of the class,
so why not for users of the class as well.
(Of course if you're using C++,
the structure of the vtable is compiler-dependant,
but it is still *implied* by the class definition,
and is visible to other C++ code that uses the class.)
The structure of a C++ vtable isn't defined
in *any* public C++ header [file].
I don't see any reason why it should be defined
in any public C header file.
What is happening here is that the C programmer
is playing the role of a C++ compiler in simulating inheritance.
The C programmer can and should infer
the structure of the virtual function table from the definition
of class Foo (struct Foo + virtual function declarations).
As an aside, note that the virtual methods themselves need to
be visible directly (not just through pointers) for a couple
of reasons. First, Bar_dtor should call Foo_dtor.

Second, Bar might want to inherit some virtual methods of Foo.
For example, to inherit f, we'd set the second member of
g_Bar_vtable to Foo_f instead of Bar_f.


Run-time polymorphism has been discussed at length
in the comp.lang.c newsgroup. See Google Groups

http://groups.google.com/

and search for

Tisdale Shape group:comp.lang.c.*

Both Re: "class" in C and Re: C version of C++'s virtual functions
contain an ANSI C implementation of Bjarne Stroustrups Shape class.
Jul 22 '05 #64
Sorry I'm slow in replying. I was out of time and offline for a week.
Please do not construe my silence as agreement.

"E. Robert Tisdale" <E.**************@jpl.nasa.gov> wrote in message news:<cb**********@nntp1.jpl.nasa.gov>...
Niklas Borson wrote:
E. Robert Tisdale wrote:
The user should *not* call the functions out of the vtable directly
but implement *virtual* functions in foo.c or bar.c that do so.
If I understand correctly, you're saying [that]
the users of the class should call a wrapper function
which in turn calls the actual function
through the pointer in the vtable.
Yes, one could do this.


What I am saying is that this is what your C++ compiler does for you.


Maybe your compiler does this, but not mine. Here's an example:

class Foo {
public:
virtual ~Foo();
virtual void Hello();
};
void Test(Foo* foo)
{
foo->Hello();
}

And here's the assembly code my compiler generates for Test:

?Test@@YAXPAVFoo@@@Z PROC NEAR
mov ecx, DWORD PTR _foo$[esp-4]
mov eax, DWORD PTR [ecx]
jmp DWORD PTR [eax+4]
?Test@@YAXPAVFoo@@@Z ENDP

The first instruction loads the foo parameter into a register.
The second instruction loads the vtable pointer into a different
register. The third instruction performs a tail call by jumping
to the entry point of the Hello function, which it gets directly
from the vtable.

In short, the Test function accesses the vtable directly without
calling a wrapper function.
A virtual function is actually a wrapper
(that's why it's called a virtual function) that calls
the actual function through the corresponding function pointer
in the virtual function table.
According to Stroustrup, the word virtual means "may be redefined
later in a class derived from this one". Nothing about wrapper
functions there.
Personally,
I don't see the advantage of this extra function call.
IMO, exposing the structure of the vtable
does not violate encapsulation.

It doesn't expose the class's data, for example.
It tells you only what virtual functions the class has --
i.e., its interface.


No!
It is an implementation detail.


It's an implementation detail of the virtual call mechanism.
That's not the same thing as exposing the representation or
inner workings of the class.
Siemel Naran used an array
to represent the virtual function table.
Which did not work very well because (1) all the function
pointers had to have the same type, and (2) the call site
had to specify the array index of the virtual function
rather than its name.
Moreover, anyone who wants to derive from the class
needs to know the structure of the vtable anyway so
as to provide a compatible vtable for the derived class.


That's because the C computer programming language
does *not* support inheritance.

Yes, the application programmer (user) must know the *order*
in which function pointers appear in struct Foo_VTable


The user needs to know the order and types of the function
pointers, which is to say *everything* about Foo_VTable.
but the application programmer does *not* need the definition
of struct Foo_VTable to define struct Bar_VTable.
The implementor of Bar_VTable needs to ensure that it has
the same members in the same order as Foo_VTable. Therefore
he needs access to the definition of Foo_VTable, or
equivalent documentation.

He may not actually *reference* that definition in the code,
but that doesn't mean it's hidden or encapsulated in any
meaningful way.
The structure of a C++ vtable isn't defined
in *any* public C++ header [file].
It is implied by the class definition, which is typically in
a header file. That is, the compiler can deduce the vtable
layout from the class definition, though *how* it does so
(or whether there's a vtable at all) is implementation
dependant.

See the example assembler output I gave earlier. To generate
the object code for the Test function, the compiler relied on
its knowledge of the vtable layout for Foo, which it inferred
from the class definition.
I don't see any reason why it should be defined
in any public C header file.
What is happening here is that the C programmer
is playing the role of a C++ compiler in simulating inheritance.
Exactly. The programmer is playing the role of the compiler.
Therefore, things like vtables and virtual calls, which a C++
compiler creates for you, must be coded explicitly in C.
The C programmer can and should infer
the structure of the virtual function table from the definition
of class Foo (struct Foo + virtual function declarations).
What virtual function declarations? There is no such thing in C.
In C++ the compiler determines the vtable layout (or whatever)
based on the virtual function declarations. In C, the programmer
must determine the vtable layout. A vtable structure seems like
a natural and obvious way of doing so.

Yes you could use wrapper functions to make the virtual function
calls, but this is not what a typical C++ compiler does. Moreover,
since implementors of derived classes still need to know both the
virtual call mechanism and the vtable layout for the base class,
hiding the actual declaration of the vtable does not actually
buy you anything in terms of encapsulation.
Run-time polymorphism has been discussed at length
in the comp.lang.c newsgroup. See Google Groups

http://groups.google.com/

and search for

Tisdale Shape group:comp.lang.c.*


I did. Perhaps you didn't notice that you and I both participated
in that thread. (I posted under a different email address then, but
used my real name then and now.) At the time, you argued that it's
impossible to do OOP in C because it's not really OO unless you use
specific language features, e.g., keywords like class and virtual.
I argued to the contrary. Now you appear to have changed your tune,
and our quibble is over merely *how* one might implement virtual
functions in C. (Of course, I'm not saying there's only one way,
just that my way is valid and reasonable. A better way, of course,
is to just use C++.)
Jul 22 '05 #65
Niklas Borson wrote:
Sorry I'm slow in replying.
I was out of time and offline for a week.
Please do not construe my silence as agreement.
Please do not construe my silence as agreement.
E. Robert Tisdale wrote:

Here's an example:

class Foo {
public:
virtual ~Foo(void);
virtual void Hello(void);
};

void Test(Foo* foo) {
foo->Hello();
}

And here's the assembly code my compiler generates for Test:

?Test@@YAXPAVFoo@@@Z PROC NEAR
mov ecx, DWORD PTR _foo$[esp-4]
mov eax, DWORD PTR [ecx]
jmp DWORD PTR [eax+4]
?Test@@YAXPAVFoo@@@Z ENDP
Did you just forget to show us the vtable?
The first instruction loads the foo parameter into a register.
The second instruction loads the vtable pointer into a different
register. The third instruction performs a tail call
by jumping to the entry point of the Hello function,
which it gets directly from the vtable.
How did your compiler know where to get the entry point for Hello?
In short, the Test function accesses the vtable directly
without calling a wrapper function.
Does it surprise you
that the C++ compiler inline'd the wrapper function?
According to Stroustrup, the word virtual means
"may be redefined later in a class derived from this one".
Nothing about wrapper functions there.
You don't show us a derived class
with a redefined "virtual" function.
How is Stroustup's remark relevant?

Which did not work very well because
(1) all the function pointers had to have the same type, and
(2) the call site had to specify the array index
of the virtual function rather than its name.
I agree that it's ugly and amy invoke "undefined behavior"
as far as the ANSI/ISO C standards are concerned
but it *does* work and it ports everywhere.

The user needs to know the order and types of the function
pointers, which is to say *everything* about Foo_VTable.
Just as the C++ compiler knows these things
*without* any public definition of the virtual function table.

The implementor of Bar_VTable needs to ensure that
it has the same members in the same order as Foo_VTable.
Therefore, he needs access to the definition of Foo_VTable,
or equivalent documentation.
I agree. C programmers must know enough about a Foo_VTable
to define a Bar_VTable correctly.
But neither definition should be published in a public header file.
He may not actually *reference* that definition in the code,
but that doesn't mean [that]
it's hidden or encapsulated in any meaningful way.
Correct!
And that's one very good reason why C++ exists.
C just doesn't provide the protection that is required
to write reliable object oriented programs.
The structure of a C++ vtable isn't defined
in *any* public C++ header [file].


It is implied by the class definition,
which is typically in a header file.
That is, the compiler can deduce the vtable
layout from the class definition, though *how* it does so
(or whether there's a vtable at all) is implementation
dependant.

See the example assembler output I gave earlier.
To generate the object code for the Test function,
the compiler relied on its knowledge of the vtable layout for Foo,
which it inferred from the class definition.
I don't see any reason why it should be defined
in any public C header file.
What is happening here is that the C programmer
is playing the role of a C++ compiler in simulating inheritance.


Exactly. The programmer is playing the role of the compiler.
Therefore, things like vtables and virtual calls, which a C++
compiler creates for you, must be coded explicitly in C.
The C programmer can and should infer
the structure of the virtual function table from the definition
of class Foo (struct Foo + virtual function declarations).


What virtual function declarations?
There is no such thing in C.
In C++ the compiler determines the vtable layout (or whatever)
based on the virtual function declarations.
In C, the programmer must determine the vtable layout.
A vtable structure seems like a natural and obvious way of doing so.

Yes you could use wrapper functions to make the virtual function
calls, but this is not what a typical C++ compiler does. Moreover,
since implementors of derived classes still need to know both the
virtual call mechanism and the vtable layout for the base class,
hiding the actual declaration of the vtable does not actually
buy you anything in terms of encapsulation.

Run-time polymorphism has been discussed at length
in the comp.lang.c newsgroup. See Google Groups

http://groups.google.com/

and search for

Tisdale Shape group:comp.lang.c.*

I did. Perhaps you didn't notice that
you and I both participated in that thread.
(I posted under a different email address then,
but used my real name then and now.)
I didn't realize that.
At the time, you argued that it's impossible to do OOP in C
because it's not really OO unless you use specific language features,
e.g., keywords like class and virtual.
You probably have me confused with someone else.
I argued to the contrary. Now you appear to have changed your tune,
and our quibble is over merely *how* one might implement virtual
functions in C. (Of course, I'm not saying [that]
there's only one way, just that my way is valid and reasonable.
A better way, of course, is to just use C++.)

Jul 22 '05 #66
"E. Robert Tisdale" <E.**************@jpl.nasa.gov> wrote in message news:<cc**********@nntp1.jpl.nasa.gov>...
Niklas Borson wrote:
E. Robert Tisdale wrote:

Here's an example:

class Foo {
public:
virtual ~Foo(void);
virtual void Hello(void);
};

void Test(Foo* foo) {
foo->Hello();
}

And here's the assembly code my compiler generates for Test:

?Test@@YAXPAVFoo@@@Z PROC NEAR
mov ecx, DWORD PTR _foo$[esp-4]
mov eax, DWORD PTR [ecx]
jmp DWORD PTR [eax+4]
?Test@@YAXPAVFoo@@@Z ENDP
Did you just forget to show us the vtable?


It wasn't necessary or relevant. The point was to show how the
virtual function call was made at the call site (under this
particular implementation).
The first instruction loads the foo parameter into a register.
The second instruction loads the vtable pointer into a different
register. The third instruction performs a tail call
by jumping to the entry point of the Hello function,
which it gets directly from the vtable.


How did your compiler know where to get the entry point for Hello?


The compiler has access to the definition of the Foo class. Therefore
it knows that Hello is the second virtual function in the class so it
obtains its address by accessing the second slot in the vtable. In this
case that's the last instruction: jmp DWORD PTR [eax+4]
In short, the Test function accesses the vtable directly
without calling a wrapper function.


Does it surprise you
that the C++ compiler inline'd the wrapper function?


I see no reason to suppose that a wrapper function ever existed. I
certainly didn't define it, and can't imagine why the C++ compiler
would define one only to optimize it away later.
According to Stroustrup, the word virtual means
"may be redefined later in a class derived from this one".
Nothing about wrapper functions there.


You don't show us a derived class
with a redefined "virtual" function.
How is Stroustup's remark relevant?


It's relevant because you had claimed that a virtual function was
a wrapper function, i.e., that that's what virtual meant. Clearly,
that's not what Stroustrup thinks it means, or anyone else as far
as I know.
Which did not work very well because
(1) all the function pointers had to have the same type, and
(2) the call site had to specify the array index
of the virtual function rather than its name.


I agree that it's ugly and amy invoke "undefined behavior"
as far as the ANSI/ISO C standards are concerned
but it *does* work and it ports everywhere.

The user needs to know the order and types of the function
pointers, which is to say *everything* about Foo_VTable.


Just as the C++ compiler knows these things
*without* any public definition of the virtual function table.


As I said, it's implied by the class definition. The compiler
must have access to the class definition in order to know how
to make a virtual function call.
The implementor of Bar_VTable needs to ensure that
it has the same members in the same order as Foo_VTable.
Therefore, he needs access to the definition of Foo_VTable,
or equivalent documentation.


I agree. C programmers must know enough about a Foo_VTable
to define a Bar_VTable correctly.
But neither definition should be published in a public header file.


Why not? You never make a case for this.
He may not actually *reference* that definition in the code,
but that doesn't mean [that]
it's hidden or encapsulated in any meaningful way.


Correct!


Note that "it" in the last sentence you quoted refers to the
vtable, not to the class implementation.

My point is that there's no reason to hide the vtable definition
in an implementation file because users of the class need to
know what it looks like anyway.
And that's one very good reason why C++ exists.
C just doesn't provide the protection that is required
to write reliable object oriented programs.


I agree it makes more sense to do OOP in C++. That's one reason
it exists, after all. However, I also think you're twisting my
words. You *can* hide a "class" implementation in C if you choose.
The only thing you can't effectively hide is the virtual function
call mechanism and the vtables -- again, because what is implicit
in C++ (the vtable/virtual call mechansim) must be explicit in a
C program because of the lack of direct language support for
polymorphism.
At the time, you argued that it's impossible to do OOP in C
because it's not really OO unless you use specific language features,
e.g., keywords like class and virtual.


You probably have me confused with someone else.


Nope. The thread is still accessible on google if you care to
see for yourself.
Jul 22 '05 #67
On Wed, 23 Jun 2004 20:11:31 +0300, Ioannis Vranos
<iv*@guesswh.at.grad.com> wrote:
JKop wrote:
Is reinterpret_cast stupid, by which I mean does it do any processing at
all? For example, take the following:

unsigned char jk;

reinterpret_cast<unsigned long&>(jk) = 4000000000UL;



Reinterpret_cast performs a value conversion. It doesn't modify anything
on the implementation of jk. So the above has essentially no effect. It
is as if you had written
reinterpret_cast<unsigned long&>(jk);


No, reinterpret_casting to a reference type is equivalent to the
pointer version. e.g.

*reinterpret_cast<unsigned long*>(&jk) = 4000000000UL;

which is obviously very bad news. The other examples further down also
look either ill-formed or undefined behaviour.

Tom
--
C++ FAQ: http://www.parashift.com/c++-faq-lite/
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
Jul 22 '05 #68
On Wed, 23 Jun 2004 18:49:49 GMT, JKop <NU**@NULL.NULL> wrote:
JKop posted:
This behavior also applies to types other than class types. For
instance, static_cast can be used to convert from an int to a char.
However, the resulting char may not have enough bits to hold the entire
int value. Again, it is left to the programmer to ensure that the
results of a static_cast conversion are safe.
This excerpt seems to be bullshit. Try running the following on your system.
If the above was true, then the end output should be all 255, assuming that
your system is 8-Bit char and 32-Bit long.
#include <iostream>

int main(void)
{
unsigned char jk[4] = { 0, 0, 0, 0 };

std::cout << "jk[0] == " << (int)jk[0]
<< "\r\njk[1] == " << (int)jk[1]
<< "\r\njk[2] == " << (int)jk[2]
<< "\r\njk[3] == " << (int)jk[3]
<< std::endl;

std::system("PAUSE");

static_cast<unsigned long>(jk[0]) = 0xFFFFFFFF;


The above line is ill-formed. Perhaps you meant:
reinterpret_cast<unsigned long&>(jk[0]) = 0xFFFFFFFF;
static_cast isn't as special as I thought. I thought it would've been able
to achieve what unions do. Ah well!


That's what reinterpret_cast can do.

Tom
--
C++ FAQ: http://www.parashift.com/c++-faq-lite/
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
Jul 22 '05 #69
tom_usenet posted:
static_cast<unsigned long>(jk[0]) = 0xFFFFFFFF;


The above line is ill-formed. Perhaps you meant:
reinterpret_cast<unsigned long&>(jk[0]) = 0xFFFFFFFF;

Try compile that.

static_cast isn't as special as I thought. I thought it would've been
able to achieve what unions do. Ah well!


That's what reinterpret_cast can do.

See my thread entitled "accessor_cast".
-JKop
Jul 22 '05 #70
On Mon, 05 Jul 2004 18:13:42 GMT, JKop <NU**@NULL.NULL> wrote:
tom_usenet posted:
static_cast<unsigned long>(jk[0]) = 0xFFFFFFFF;
The above line is ill-formed. Perhaps you meant:
reinterpret_cast<unsigned long&>(jk[0]) = 0xFFFFFFFF;

Try compile that.


It compiles fine (on 2 highly standards compliant compilers). The
static cast version doesn't of course, since you're trying to assign a
value to an rvalue.
See my thread entitled "accessor_cast".


Will do.

Tom
--
C++ FAQ: http://www.parashift.com/c++-faq-lite/
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
Jul 22 '05 #71
tom_usenet posted:

reinterpret_cast<unsigned long&>(jk[0]) = 0xFFFFFFFF;

Sorry I didn't realize you'd changed it to a "reinterpret_cast". I just
glanced at it and the "&" caught my eye.
-JKop
Jul 22 '05 #72

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

0
by: softwareengineer2006 | last post by:
All Interview Questions And Answers 10000 Interview Questions And Answers(C,C++,JAVA,DOTNET,Oracle,SAP) I have listed over 10000 interview questions asked in interview/placement test papers for...
0
by: Jobs | last post by:
Download the JAVA , .NET and SQL Server interview sheet and rate yourself. This will help you judge yourself are you really worth of attending interviews. If you own a company best way to judge if...
2
by: Jobs | last post by:
Download the JAVA , .NET and SQL Server interview with answers Download the JAVA , .NET and SQL Server interview sheet and rate yourself. This will help you judge yourself are you really worth of...
0
by: connectrajesh | last post by:
INTERVIEWINFO.NET http://www.interviewinfo.net FREE WEB SITE AND SERVICE FOR JOB SEEKERS /FRESH GRADUATES NO ADVERTISEMENT
2
by: freepdfforjobs | last post by:
Full eBook with 4000 C#, JAVA,.NET and SQL Server Interview questions http://www.questpond.com/SampleInterviewQuestionBook.zip Download the JAVA , .NET and SQL Server interview sheet and rate...
0
by: freesoftwarepdfs | last post by:
Ultimate list of Interview question website.....Do not miss it http://www.questpond.com http://msdotnetsupport.blogspot.com/2007/01/net-interview-questions-by-dutt-part-2.html...
0
by: ramu | last post by:
C# Interview Questions and Answers8 http://allinterviewsbooks.blogspot.com/2008/07/c-interview-questions-and-answers8.html C# Interview Questions and Answers7...
0
by: reema | last post by:
EJB Interview Questions http://interviewdoor.com/technical/EJB-Interview-Questions.htm CSS Interview Questions http://interviewdoor.com/technical/CSS-Interview-Questions.htm C Interview Questions...
0
by: reema | last post by:
EJB Interview Questions http://interviewdoor.com/technical/EJB-Interview-Questions.htm CSS Interview Questions http://interviewdoor.com/technical/CSS-Interview-Questions.htm C Interview Questions...
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
1
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...
0
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and...
0
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.