Виртуальные функции - зло?

Teonates
Offline
Зарегистрирован: 22.10.2016

Преветствую форумчан! Сегодня столкнулся с совершенно невероятным непонятным нечто. В общем - убиваются данные в памяти. И так крутил и этак, пока не понял, что всё очень плохо. И так, постановка:

Имеем класс А и класс B. Создаем в рантайме (через new) соответствуюзие экземпляры. В классе А виртуальные функции отсутствуют, но в нем выделяется буфер. В классе B присутствует виртуальная функция, которая вызывается. Друг о друге классы пока что не подозревают. Но, как только вызывается виртуальная функция 'экземпляра B, в которой происходит инициализация двух переменных, начинает портиться буфер экземпляра А. Продебажил указатели и вижу:

buffer а(А) ptr: 871

ptr to object b(B): 867

sizeof(B): 5

т.е. получается "нахлест" в один байт! как такое может быть? это же просто эпичный фейл. тепеь фокус - убираем идентификатор виртуальности и размер становится уже 3, при тех же адресах.

Магия? Бубен? Куда бы постучать? 

PS:

Atmel Studio 7 (Version: 7.0.1188 - ) Arduino IDE for Atmel Studio 7 Version: 1609.4.3

 
 
 

 

 

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Да, почему "зло"? Вполне себе добро, если "готовить уметь".

Про пример ничего не скажу, т.к. его не видел.

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

У меня машина издает странные звуки, шир-шир, хра-хра, скажите, что с ней не так?

Teonates
Offline
Зарегистрирован: 22.10.2016

Думал что доступно описал проблему. Прошу прощение за невежество :) И так, имеем основной ino-файл

#include "FastDisplay/FastDisplay.h"
#include "BaseFontClass.h"

FastDisplay * myFastDisplay;
BaseFontClass * baseFont;

void setup()
{	
	Serial.begin(921600);
	myFastDisplay = new FastDisplay();
	baseFont = new BaseFontClass();
	//Serial.println("lets start");
	myFastDisplay->init( 8, 4 );
	//Serial.println("end...");

	baseFont->init();

	Serial.println("+++");
}

 

Далее заголовочный файл FastDisplay.h, который был условно обозначен "А"

class FastDisplay
{
private:
	int CS;
	int devicesCount;
	byte * hiddenScreen;
protected:
public:
	FastDisplay();
	void init(int cs, int devices);
};

 

Ему соответствует cpp

FastDisplay::FastDisplay()
{
	//currentFont = NULL;
}

void FastDisplay::init(int cs, int devices)
{
	
	CS = cs;
	devicesCount = devices;
	hiddenScreen = new byte[devices*8];
	Serial.println("--");
	Serial.print("a(A) ptr: ");	Serial.println((int)this);
	Serial.print("sizeof(A): ");	Serial.println(sizeof(FastDisplay));
	Serial.print("a(A) buffer ptr: ");	Serial.println((int)hiddenScreen);
}

 

Заголовок условного класса "B"

struct Symbol
{
	byte sim;
	byte width;
	byte data[8];
};


class BaseFontClass
{
 private:
	Symbol * sims;
	byte count;
 public:
	BaseFontClass();
	virtual void init();
};

 

cpp к нему

BaseFontClass::BaseFontClass()
{
	sims = NULL;
	count = 0;
}

void BaseFontClass::init()
{
	Serial.print("b(B) ptr: ");Serial.println((int)this);
	Serial.print("sizeof(B): ");Serial.println(sizeof(BaseFontClass));
	//this->sims = NULL;
	//this->count = 2;
}

 

Вот такие не хитрые исходники. Берем теперь это добро и запускаем:

--

a(A) ptr: 738

sizeof(A): 6

a(A) buffer ptr: 750

b(B) ptr: 746

sizeof(B): 5

+++

 

указатель на только что созданный буфер указывает на последний байт объекта "b". Делаем магию, убираем virtual

--

a(A) ptr: 738

sizeof(A): 6

a(A) buffer ptr: 750

b(B) ptr: 746

sizeof(B): 3

+++

 

И количество wtf в час переваливает все разумные пределы.

Logik
Offline
Зарегистрирован: 05.08.2014

Подописывал инклуды, собрал, залил в Нану. Выдало

--
a(A) ptr: 545
sizeof(A): 6
a(A) buffer ptr: 560
b(B) ptr: 553
sizeof(B): 5
+++
 
Перекрытие отсутствует: 553+5<560.
Думаю у Вас проблема в следующем: строка Serial.begin(921600); выдает в Вас любителя скорости и экстрима... Вы компилятор дорабатывали, ну чтоб быстрей было?
Teonates
Offline
Зарегистрирован: 22.10.2016

Logik пишет:

Подописывал инклуды, собрал, залил в Нану. 

 
Принимайте благодарочку :) Натолкнул на мысль этой фразой и решил я прожать Clean Solution, перед тем как пересобрать проект заново из исходников - взлетело :)
Всем спасибо, опыт получен и вопрос закрыт