AVR C++ (cpp)

Go To Last Post
73 posts / 0 new

Pages

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
No. I just assumed it was similar to a regular class data member.

No. Read my posts above discussing the tech stuff.

Quote:

Where else would it be located? I guess it could be like a "static" member.

That could be one option. Or it could be a separate entity.

Quote:
I believe C++ structs/classes can be bigger than equivalent C structs because C++ structs/classes can have extra stuff hidden in them. Is that true?

They can be bigger but then they are not equivalent.

I know of two extra memory costs of C++ classes/structs as compared to C structs: The v-tables that we are discussing here, and stuff needed for RTTI (Run-Time Type Information).

As we seem to have reached consensus on above, there only needs to be one v-table per class. Apart from this, every object that has an associated v-table have a hidden data member that is a pointer to that table. The one I called __vtable above.

Any decent compiler should avoid generating a v-table, and the pointer to it, for a class that does not have/inherit virtual member functions.

For the RTTI I am less sure (need to think/read). No big cost, most likely something like a generated type ID (one ID value for each class, but stored in each object) and some kind of representation of the inheritance hierarchy (so that one can answer question like "is this animal a Cat?").

It's been a good many years since I played with RTTI, never used it in embedded stuff, and it is somewhat esoteric anyway. I would expect it to follow the normal principle re C++ performance (as compared to C): If you don't use it then it will not have any cost.

-----

Just to try to summarize the v-table discussion: On RAM-challenged AVRs, saving even a small amount of RAM is often very valuable. So even if there are only a few v-tables (and remember - one per class, not per object), occupying not so many bytes, it would be A Good Thing if they could be located in flash memory instead. Example: 64 bytes of RAM used by v-tables might be a real pain. OTOH, 64 bytes of flash used generally hurts much less.

This is what it is about. The recent excursions was an effect of Chaunceys erroneous "they must be able to be modified" remark, and me going through the roof. Enjoy the tech talk if you like, or just ignore it.

The bottom line is: There are no principal obstacles for placing v-tables in flash. Someone "just" needs to implement it in avr-gcc.

Is this a big problem? I speculate that using virtual functions on AVRs are quite rare anyway so it is not a wide-spread pain. An app that requires virtual functions is likely rather advanced anyway, and would not likely running on any of the small(ish) AVRs. (And if the largest Mega AVR does not have enough RAM, then just move up to a less challenged uC family, like the XMegas or 32-bit AVRs or perhaps some Cor[cough-cough]tex-Mn.) If anyone has real-world experiences of where v-tables in RAM has been an actual and substantial pain, then I for one would like to hear about it.

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

wow - my restart on this thread with the question re flash v-tables led to some discussion!!

my 2 cents worth on bloat from some reasonably limited experience.... when I first started to use c++ and in particular templates my code size went crazy.

when I started to read the listing and think about the code size I was able to change my design to still deliver the oo benefits but make the code smaller.

I have found I use templates to allow const data that varies per instance to be placed in flash. i write a base class that does all the work and then wrap it in a template that creates any instance specific data; whereas it would be "normal" to put this in ram on a bigger computer I prefer to put it in flash on an atmega16.

Overall I am a fan of c++ on the atmega!

regards
Greg

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

JohanEkdahl wrote:
The bottom line is: There are no principal obstacles for placing v-tables in flash. Someone "just" needs to implement it in avr-gcc.

It's not entirely straightforward. It would have to be an option, to allow compatibility with existing libraries.

Preferably an option that could be turned off and on in the source code - to allow a mix. A #pragma could do that.

Sid

Life... is a state of mind

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Does the vtable get constructed at run time or compile/link time?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The v-table is a table of function pointers. Just like when setting up some such in C, it happens at compile time.

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

A sensible toolchain would create it at link time, so that is probably the case for avrgcc.

Sid

Life... is a state of mind

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

JohanEkdahl wrote:
The v-table is a table of function pointers. Just like when setting up some such in C, it happens at compile time.

It can't happen at compile time. The member functions may be in different compilation units.

Although maybe it would be correct to say that the compiler sets it up and the linker fills in the missing pieces.

Sid

Life... is a state of mind

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I guess the vtables are copied from flash to RAM at program startup, like most initialized data is.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

steve17 wrote:
I guess the vtables are copied from flash to RAM at program startup, like most initialized data is.

The point would be that they seem to be constant, so they could be kept in flash.

Sid

Life... is a state of mind

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hmm.. I'm sure I answered Chaunceys correction of my terminology abuse above, but that post never made it (most likely "operator error"). So again:

Chauncey wrote:
It can't happen at compile time. The member functions may be in different compilation units.

Yup. I should have used a better term, e.g. "build time" (as in "not run time")
.
steve17 wrote:
I guess the vtables are copied from flash to RAM at program startup, like most initialized data is.

That is how I think it is done too. There is no reason to do it in any other way as I see it, and that mechanism is already in place. As I've said before, you might see the v-tables as something very similar to a table/struct/array of function pointers in C, with the function pointers (addresses) established at build time. Those would be "constructed" at build time, in the sense that the addresses are established and the table "filled in", and placed in the .data memory section. In the startup code there is code to copy .data to RAM.

I imagine that C++ v-tables are handled the same way. If you consider this copying a part of construction then you could say that part of the construction happens at run-time.

But I consider this just a technical manouvre of the Harvard architecture, not something like a C++ principle. On a Von Neumann architecture the .data memory section would just be loaded into some RAM region, just like the .text section. No special manouvre specific for the v-tables would be needed.

All this not in any way to argue over how to interpret the expression "construction of v-tables in avr-gcc" but merely to try to clear out how I see the tech stuff.

Slightly aside, but still: When thinking of how C++ actually does things it is often possible to think about how you would do the same thing in C. In fact, the first C++ compiler (CFRONT) translated from C++ to C, the latter used "merely" as an intermediate stage being fed into a C compiler. I sometimes use a similar approach when teaching/explaining what goes on behind the scenes in C++.

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

There is a difference, though, between function pointers in C and v-tables in C++.

The function pointers in C are created by the user, while the v-tables in C++ are created by the compiler.

The former may change at runtime, the latter won't.

Sid

Life... is a state of mind

Last Edited: Sat. Sep 1, 2012 - 12:11 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes. There is a slight complication of course if the vtables are left in flash. The technique for reading data from flash is different from the technique for reading from RAM, so the software that reads it must be aware it is in flash.

I wonder if it will ever be possible to read data from flash using the same instructions that are used to read data from RAM. The Xmega EEPROM can be read this way.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Code is read from flash all the time, why would constant data be any different ?

Sid

Life... is a state of mind

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Johan,

To see what actually happens I tried to turn your example into some real code:

#include 

class Super {
	public:
   virtual void f() { PORTA = 0xAA; };
   virtual void g() {  PORTB = 0xBB; };
};

class Sub : public Super {
public:
   virtual void f() { PORTC = 0xCC; };
   virtual void g() { PORTD = 0xDD; };
}; 

int main(void)
{
	Super super;
	Sub sub;
	
	super.f();
	super.g();
	sub.f();
	sub.g();
}

And this generates:

00000054 <__ctors_end>:
  54:	11 24       	eor	r1, r1
  56:	1f be       	out	0x3f, r1	; 63
  58:	cf e5       	ldi	r28, 0x5F	; 95
  5a:	d4 e0       	ldi	r29, 0x04	; 4
  5c:	de bf       	out	0x3e, r29	; 62
  5e:	cd bf       	out	0x3d, r28	; 61

00000060 <__do_copy_data>:
  60:	10 e0       	ldi	r17, 0x00	; 0
  62:	a0 e6       	ldi	r26, 0x60	; 96
  64:	b0 e0       	ldi	r27, 0x00	; 0
  66:	ec ea       	ldi	r30, 0xAC	; 172
  68:	f0 e0       	ldi	r31, 0x00	; 0
  6a:	02 c0       	rjmp	.+4      	; 0x70 <__do_copy_data+0x10>
  6c:	05 90       	lpm	r0, Z+
  6e:	0d 92       	st	X+, r0
  70:	a0 36       	cpi	r26, 0x60	; 96
  72:	b1 07       	cpc	r27, r17
  74:	d9 f7       	brne	.-10     	; 0x6c <__do_copy_data+0xc>

00000076 <__do_clear_bss>:
  76:	10 e0       	ldi	r17, 0x00	; 0
  78:	a0 e6       	ldi	r26, 0x60	; 96
  7a:	b0 e0       	ldi	r27, 0x00	; 0
  7c:	01 c0       	rjmp	.+2      	; 0x80 <.do_clear_bss_start>

0000007e <.do_clear_bss_loop>:
  7e:	1d 92       	st	X+, r1

00000080 <.do_clear_bss_start>:
  80:	a0 36       	cpi	r26, 0x60	; 96
  82:	b1 07       	cpc	r27, r17
  84:	e1 f7       	brne	.-8      	; 0x7e <.do_clear_bss_loop>
  86:	0e 94 49 00 	call	0x92	; 0x92 
8a: 0c 94 54 00 jmp 0xa8 ; 0xa8 <_exit> 0000008e <__bad_interrupt>: 8e: 0c 94 00 00 jmp 0 ; 0x0 <__vectors> 00000092
: #define F_CPU 1234567UL #include class Super { public: virtual void f() { PORTA = 0xAA; }; 92: 8a ea ldi r24, 0xAA ; 170 94: 8b bb out 0x1b, r24 ; 27 virtual void g() { PORTB = 0xBB; }; 96: 8b eb ldi r24, 0xBB ; 187 98: 88 bb out 0x18, r24 ; 24 }; class Sub : public Super { public: virtual void f() { PORTC = 0xCC; }; 9a: 8c ec ldi r24, 0xCC ; 204 9c: 85 bb out 0x15, r24 ; 21 virtual void g() { PORTD = 0xDD; }; 9e: 8d ed ldi r24, 0xDD ; 221 a0: 82 bb out 0x12, r24 ; 18 super.f(); super.g(); sub.f(); sub.g(); } a2: 80 e0 ldi r24, 0x00 ; 0 a4: 90 e0 ldi r25, 0x00 ; 0 a6: 08 95 ret

but as you can see it's simply inlined the functions. Also while there is code for both _do_copy_data and _do_clear_bss you'll notice that the start and end condition in both cases is 0x0060 (mega16) so neither loop actually does anything.

So how can I turn this into some example code that really does require vtables to be created and copied from flash to RAM?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

That's funny! I was just about to post some stuff from an example I've been tinkering with in the pauses while washing clothes.. (And our class names are identical, but I've just decided to tinker some more changing the name of my f() to set() so that I can have a clear() to prepare for the next sub test...)

Quote:
So how can I turn this into some example code that really does require vtables to be created and copied from flash to RAM?

Oh you C programmers... If you don't need what C++ offers, then don't use it. :wink:

1. Don't code for inlining:

class Super {
public:
   virtual void f();
   virtual void g();
}; 
void Super::f() { PORTA = 0xAA; };
void Super::g() {  PORTB = 0xBB; };

2. Do the REALLY interesting call! (I.e. actually use what virtual functions offer. Your example could do just as well with all 'virtual' removed...)

int main(void)
{
   Super * pSuper;
   Sub sub;
   pSuper = ⊂
   pSuper->f();
}

You've sort of taken the edge off my example/investigation. If I don't finish and come back here with details, let me at least quote from my MAP file:

.data           0x00800100        0xc load address 0x000000d0
                0x00800100                PROVIDE (__data_start, .)
 *(.data)
 .data          0x00800100        0x0 c:/program files/atmel/atmel studio 6.0/extensions/atmel/avrgcc/3.4.0.65/avrtoolchain/bin/../lib/gcc/avr/4.6.2/../../../../avr/lib/avr4/crtm88.o
 .data          0x00800100        0xc avr-gcc Cxx polymorphism investigation.o
                0x00800100                vtable for Super
                0x00800106                vtable for Sub
 .data          0x0080010c        0x0 c:/program files/atmel/atmel studio 6.0/extensions/atmel/avrgcc/3.4.0.65/avrtoolchain/bin/../lib/gcc/avr/4.6.2/avr4\libgcc.a(_exit.o)
 .data          0x0080010c        0x0 c:/program files/atmel/atmel studio 6.0/extensions/atmel/avrgcc/3.4.0.65/avrtoolchain/bin/../lib/gcc/avr/4.6.2/avr4\libgcc.a(_copy_data.o)
 .data          0x0080010c        0x0 c:/program files/atmel/atmel studio 6.0/extensions/atmel/avrgcc/3.4.0.65/avrtoolchain/bin/../lib/gcc/avr/4.6.2/avr4\libgcc.a(_clear_bss.o)
 *(.data*)
 *(.rodata)
 *(.rodata*)
 *(.gnu.linkonce.d*)
                0x0080010c                . = ALIGN (0x2)
                0x0080010c                _edata = .
                0x0080010c                PROVIDE (__data_end, .)

Please notice the MAP information for two vtables. They are in the .data segment. They will be handled not in any special way, but as a part of __do_copy_data .

I am looking at the virtual call in my example - it involves loading of both Y and Z registers and some other stuff and finally an ICALL. In general what you would expect.

To get down to the nitty-gritty I'd like to have something that shows me the .data segment, preferably with labels and stuff - and contents. Sort of like the .lss, but the .lss only shows me such info for the .text segment. Am I missing something, or do I just have to dive dead first into the HEX? (Please say no...).

Cliff! Let me know if you dig deeper! You are way faster than I am, and much better at the low level stuff. It would be a waste of time if I spent substantial time on an investigation and explanation if you do the same. OK?

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Oh, about the inlining: It might be that the compiler is smart enough for trivial examples to optimize away the virtual call. I turned off the optimizer.

Another observation is that the compiler seems to optimize stuff even at -O0:

#include 

class Super {
public:
  virtual void f();    
};

class Sub : public Super {
public:
  virtual void f();
};

void Super::f()
{
  PORTB = 0x55;
}

void Sub::f()
{
	PORTB = 0xAA;
}

int main(void)
{
  Super super;
  Sub sub;
  Super * pSuper;
  Sub * pSub;
  
  pSub = ⊂
  pSub->f();
  
  pSuper = &super;
  pSuper->f();
  
  pSuper = ⊂
  pSuper->f();
  
}

The thing that surprised me was that the first call became a straight RCALL. I haven't disseminated the code, but my initial speculation is that
1. since the pointer is of the most specialized type in the type hierarchy then,
2. it can not point to anything but a Sub, and thus
3. the compiler knows it can optimize the virtual/"dynamic"/late-binding/polymorphic call away and do a plain old "static"/early-binding call.

Pretty clever compiler!

I am guessing that what Cliff experienced was even "cleverer" by the compiler.

Finally: I assume that one dead certain way to force the compiler into doing a real virtual call is to let the type of the object called be determined by something volatile - e.g. the value on an I/O port.

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The only place where you actually use polymorphism in that example is in the third call. The first two would produce the same result even if the functions were non-virtual.

Sid

Life... is a state of mind

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Guys,
a small example below shows how the v-table is initialised.

#include 

class baseClass
{
	public:
		int a;
		int b;
		int c;
		baseClass(void){};
		virtual void aFunc(int data);
};

class aClass: public baseClass
{
	public:
		aClass(void)
		{
			a=0x1111;
			b=0x2222;
			c=0x3333;
		};
		void aFunc(int data);
};

void aClass::aFunc(int data)
{
	a = data;
	b = data + 1;
	c = b *3;
}

aClass a;

int main(void)
{
    a.aFunc(0x10);
	while(1)
    {
        //TODO:: Please write your application code 
    }
}

looking in the lss file generated from the above you can see that the compiler has expanded the constructor with the inclusion of the v-table population.

class aClass: public baseClass
{
	public:
		aClass(void)
		{
  d6:	84 e6       	ldi	r24, 0x64	; 100
  d8:	90 e0       	ldi	r25, 0x00	; 0
  da:	90 93 67 00 	sts	0x0067, r25
  de:	80 93 66 00 	sts	0x0066, r24
			a=0x1111;
  e2:	81 e1       	ldi	r24, 0x11	; 17
  e4:	91 e1       	ldi	r25, 0x11	; 17
  e6:	90 93 69 00 	sts	0x0069, r25
  ea:	80 93 68 00 	sts	0x0068, r24
			b=0x2222;
  ee:	82 e2       	ldi	r24, 0x22	; 34
  f0:	92 e2       	ldi	r25, 0x22	; 34
  f2:	90 93 6b 00 	sts	0x006B, r25
  f6:	80 93 6a 00 	sts	0x006A, r24
			c=0x3333;
  fa:	83 e3       	ldi	r24, 0x33	; 51
  fc:	93 e3       	ldi	r25, 0x33	; 51
  fe:	90 93 6d 00 	sts	0x006D, r25
 102:	80 93 6c 00 	sts	0x006C, r24

look at the map below you can see the object "a" is located at 0x0066. Interesting there is also a 6 byte filed at 0x0060 with is labelled for the aClass vtable. As far as I can see these 6 bytes are never used!?!

 .data          0x00800060        0x6 virtualTest.o
                0x00800060                vtable for aClass
 .data          0x00800066        0x0 d:/program files (x86)/atmel/atmel studio 6.0/extensions/atmel/avrgcc/3.4.0.65/avrtoolchain/bin/../lib/gcc/avr/4.6.2/avr5\libgcc.a(_exit.o)
 .data          0x00800066        0x0 d:/program files (x86)/atmel/atmel studio 6.0/extensions/atmel/avrgcc/3.4.0.65/avrtoolchain/bin/../lib/gcc/avr/4.6.2/avr5\libgcc.a(_copy_data.o)
 .data          0x00800066        0x0 d:/program files (x86)/atmel/atmel studio 6.0/extensions/atmel/avrgcc/3.4.0.65/avrtoolchain/bin/../lib/gcc/avr/4.6.2/avr5\libgcc.a(_clear_bss.o)
 .data          0x00800066        0x0 d:/program files (x86)/atmel/atmel studio 6.0/extensions/atmel/avrgcc/3.4.0.65/avrtoolchain/bin/../lib/gcc/avr/4.6.2/avr5\libgcc.a(_ctors.o)
 .data          0x00800066        0x0 d:/program files (x86)/atmel/atmel studio 6.0/extensions/atmel/avrgcc/3.4.0.65/avrtoolchain/bin/../lib/gcc/avr/4.6.2/avr5\libgcc.a(_tablejump.o)
 *(.data*)
 *(.rodata)
 *(.rodata*)
 *(.gnu.linkonce.d*)
                0x00800066                . = ALIGN (0x2)
                0x00800066                _edata = .
                0x00800066                PROVIDE (__data_end, .)

.bss            0x00800066        0x8
                0x00800066                PROVIDE (__bss_start, .)
 *(.bss)
 .bss           0x00800066        0x0 d:/program files (x86)/atmel/atmel studio 6.0/extensions/atmel/avrgcc/3.4.0.65/avrtoolchain/bin/../lib/gcc/avr/4.6.2/../../../../avr/lib/avr5/crtm16.o
 .bss           0x00800066        0x8 virtualTest.o
                0x00800066                a

interestingly in this contrived example even though the vtable is populated for "a" the compiler actually generates a direct call to aFunc()!

regards
Greg

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

and here is an example that uses all of the data. the pointer at the start of the variable "a" points to the vtable (it is not the acutal vtable).

The vtable is populated in ram as part of global data initialisation.

Coming all the way back to the original question.... there seems to be no practical reason why the vtable could not be in flash. similarly the vtable pointer at the start of the object data.

we just need an avr-gcc volunteer that thinks this would be something interesting to work on!!

The example I have given looks very contrived. My original interest was to use an array of class member function pointers as a way to despatch functions in a simple scheduler.

#include 

class baseClass
{
	public:
		int a;
		int b;
		int c;
		baseClass(void){};
		virtual void aFunc(int data);
};

class aClass: public baseClass
{
	public:
		aClass(void)
		{
			a=0x1111;
			b=0x2222;
			c=0x3333;
		};
		void aFunc(int data);
};

void aClass::aFunc(int data)
{
	a = data;
	b = data + 1;
	c = b *3;
}

aClass a;
//aClass b;

 
int main(void)
{
	void (aClass::*fptr) (int);
	fptr = &aClass::aFunc;
	
	aClass * ptr;
	ptr = &a;
	(ptr->*fptr)(0x30);

	
    //a.aFunc(0x10);
    //b.aFunc(0x20);
	while(1)
    {
        //TODO:: Please write your application code 
    }
}

regards
Greg

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If a v-table is set up at the beginning of the constructor, that would be the v-table for its superclass.

As illustrated earlier in this thread, the v-table for an object is not in effect until the constructor has finished. (I.e. during the construction of an object, the v-table for its superclass is used.)

Most likely, you see it in the subclass constructor because the superclass constructor is inlined.

Also note that the direct call is a direct call because that's what you told the compiler to do. You didn't use a superclass pointer to do the call. So using virtual is pointless in this case.

Sid

Life... is a state of mind

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

gregd99 wrote:
there seems to be no practical reason why the vtable could not be in flash.

One possible reason would be slower excution. I assume the address of "normal" functions are known at link time. For a virtual function, the address has to be looked up at runtime.

Sid

Life... is a state of mind

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

The only place where you actually use polymorphism in that example is in the third call.

Yup. Those cases where there for completeness. (And they revealed the fact that even at -O0 the compiler generated code for a call to a virtual function not using the v-table. :D)

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

Pages