Перейти к содержанию
    

Плавный переход C -> C++ под МК

Это не колхоз. Это C. Решение здесь - ABC (abstract virtual class), но я не знаю, какие у них накладные расходы, и применяются ли они при программировании микроконтроллеров.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

29 minutes ago, Arlleex said:

Может, это колхоз?

Не колхоз. Делаю так для установки пользовательских обработчиков в прерывании драйверов, например.

TRetVal TimDriver::setUserIrqHandler( const UserIrqHandlerNum &num, UserIrqHandler_t _handler ) {
    if (num == UserIrqHandlerNum::nLast)
        return rvSETTING_ERROR;
    m_ctrl.handler[static_cast<size_t>(num)] = _handler;
    return rvOK;
}
/// Указатель на функцию-обработчик прерывания, если драйвер позволяет использовать таковую.
typedef bool ( *UserIrqHandler_t )();

Да и вообще, использую коллбеки.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 minute ago, Arlleex said:

О, ну тогда мое представление, вроде как, даже верное:smile: 

Возможно, что есть более красивые и Си++ - правильные способы. Но я действую так, как мне проще и понятнее. Пробовал тут с месяц назад разобраться с темой вызова нестатических методов класса по указателю. Исследовал тему делегатов и прочей подобной кухни. Прочитал пару статей. И пришёл к выводу, что указатели на нестатические методы в Си++, ИМХО, несколько уродливые. Куча ограничений. Иногда проще использовать Си-подобные методы решения задач. К слову, пытался сделать обработчик прерывания нестатическим методом класса, адрес на который подставляется в таблицу векторов, расположенную в ОЗУ. Просто экспериментировал... отчасти.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Just now, Arlleex said:

О, ну тогда мое представление, вроде как, даже верное:smile: Спасибо!

Это невозможно сказать, без знания того, зачем вам c++. Если для ООП, то кардинально неверное. Если для более строгой типизации, и, может быть шаблонов - тогда может быть и верное.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Я просто хочу быть трушным программистом на C/C++:prankster2: (а как мне еще ответить на вопрос "зачем мне C++"?)
Мне нравится "конструкторский" стиль построения программы, мне нравится весь синтаксический сахар плюсов.
И все это в одном флаконе, да чтоб еще без накладных расходов (либо чтобы их наличие вызывало лишь смех).

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

27 minutes ago, haker_fox said:

несколько уродливые. Куча ограничений.

Мало статей читали )  Есть еще готовые решения на гитхабе (по поиску).

Через делегаты все прекрасно и красиво работает, "уродливую часть" прячет в себе сам делегат, для чего оно в основном и нужен - упростить текст кода, спрятав от глаз лишние и опасные вещи (при работе с указателями).

 

Вот чужой пример разных вариантов применения делегатов:

 

Spoiler

 


class DelegateSample {

	static int F(char value) {
		printf("Passed parameter: %c\n", value);
		return (char)value;
	} //F

	int instanceField;
	double A(unsigned long value, char c) {
		printf("Passed parameters: %lu, '%c; instance field: %d\n", value, c, instanceField);
		return 1.0 * instanceField / value;
	} //A

	double B(unsigned long value, char& c) const {
		printf("Passed parameters: %lu, '%c; instance field: %d\n", value, c, instanceField);
		return 1.0 * instanceField / value;
	} //B

	static double StaticMember(unsigned long value, char c) {
		printf("Passed parameters: %lu, %c\n", value, c);
		return 1.0 / value;
	} //B

	void Noret(int value) {
		printf("No return; passed parameter: %d\n", value);
	} //Noret

public:

	DelegateSample(int aField) : instanceField(aField) {}
	double InstanceMember(unsigned long, char) { return 0.1;  }

	static void Demo() {
		using namespace SA;
		printf("Single-cast delegates:\n\n");
		DelegateSample sample(11);
		DelegateSample anotherSample(12);
		int touchPoint = 1;
		auto lambda = [&touchPoint](unsigned long a, char b) -> double {
			touchPoint++;
			printf("Delegate is assigned to lambda expression\n");
			return a * 0.5;
		};
		delegate<double(unsigned long, char)> dlambda;
		dlambda = lambda; // template instantiation deduced (inferred)
		double lambdaResult = dlambda(1, 'a');
		printf("lambda result: %g, captured: %d\n", lambdaResult, touchPoint);
		auto d1 = delegate<double(unsigned long, char)>::create<DelegateSample, &DelegateSample::A>(&sample);
		auto dcompare = delegate<double(unsigned long, char)>::create<DelegateSample, &DelegateSample::A>(&sample);
		if (d1 == dcompare)
			printf("Two delegates are the same\n");
		auto d2 = delegate<double(unsigned long, char)>::create<DelegateSample, &DelegateSample::A>(&anotherSample);
		auto d3 = delegate<double(unsigned long, char&)>::create<DelegateSample, &DelegateSample::B>(&sample);
		auto d4 = delegate<double(unsigned long, char&)>::create<DelegateSample, &DelegateSample::B>(&anotherSample);
		auto d5 = delegate<int(char)>::create<&DelegateSample::F>();
		double ret1 = d1(1, 'a');
		double ret2 = d2(2, 'b');
		printf("Returned: %g, %g\n", ret1, ret2);
		char byRef = 'c';
		double ret3 = d3(3, byRef);
		byRef = 'd';
		double ret4 = d4(4, byRef);
		printf("Returned: %g, %g\n", ret3, ret4);
		d1 = d2;
		int ret5 = d5('e');
		printf("Returned: %d\n", ret5);
		printf("Returned: %g, %g\n", ret3, ret4);
		printf("\nMulticast delegates:\n\n");
		multicast_delegate<double(unsigned long, char)> md1, md2;
		if (!md2.isNull())
			md2(111, '1');
		((md1 += d1) += d2) += d2;
		md2 += d2;
		md2 += d1;
		md2 += d1;
		md2 += d1;
		md2 += delegate<double(unsigned long, char)>::create<&DelegateSample::StaticMember>();
		md2 += dlambda; // template instantiation deduced (inferred)
		if (!md1.isNull())
			md1(5, 'F');
		if (!md2.isNull())
			md2(6, 'G');
		printf("\nMulticast delegates, invocation with return:\n\n");
		md2(14, 'm');
		int closure = 0;
		md2(15, 'M', [=, &closure](size_t index, double* result) -> void {
			printf("\t\treturns: %g at %zd\n", *result, index);
			closure++;
		});
		// ----- Multicast return handlers with capture: ------------------------------------------------
		printf("Multicast return handlers with capture: ================\n");
		double total = 0;
		double first = -1;
		double last = -1;
		md2(16, 'N', [&total](size_t index, double* result) -> void {
			printf("\t\treturns: %g at %zd\n", *result, index);
			total += *result;
		});
		printf("Captured total: %g, average: %g \n", total, total/md2.size());
		md2(16, 'N', [&total, &first, &last, &md2](size_t index, double* result) -> void {
			if (index == 0) first = *result;
			if (index == md2.size() - 1) last = *result;
			printf("\t\treturns: %g at %zd\n", *result, index);
			total += *result;
		});
		printf("Captured total: %g, first: %g, last: %g \n", total, first, last);
		printf("not capturing, equivalent to md2(17, 'O'):\n");
	} //Demo

};

 

 

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

C++ это C, в котором любая задача делается чуть удобнее. Нет причин не использвать, кроме совместимости со старьем. И под старьем имеются в виду люди.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 час назад, Arlleex сказал:

А как надо тогда?

Curiously recurring template pattern

Немного дополнив пример из вики использую таким образом:

template <class T> 
struct Base
{
    void interface()
    {
        // ...
        impl()->implementation();
        // ...
    }

    static void static_func()
    {
        // ...
        T::static_sub_func();
        // ...
    }
protected:
    T* impl()               { return static_cast<T*>(this); }
    T* const impl() const   { return static_cast<T const *>(this); }
};

struct Derived : Base<Derived>
{
    void implementation();
    static void static_sub_func();
};

В классах-наследниках определяете свои реализации SetBaudRate().

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

12 minutes ago, Forger said:

Вот чужой пример разных вариантов применения делегатов:

Весь этот фарш был упразднен еще стандартом 11го года.

class MyClass {
    int f(int, bool);
};

MyClass object;

std::function<int(bool, int)> callback;

callback = [&](bool b, int i) { 
    return object.f(i, b);
}

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

18 minutes ago, rkit said:

C++ это C...

Только если вы C в последний раз видели году в 95.

42 minutes ago, Arlleex said:

Я просто хочу быть трушным программистом на C/C++

Ну, это уже лет 20 - разные, пусть и сильно похожие, языки.

В C++ настолько есть ВСЁ, что на нëм можно программировать сильно по-разному. Потому и спрашиваю - вам ООП или процедурный подход? Если процедурный, то можно коллбэки, если ООП,  то не надо колбэками костылить.

Изменено пользователем one_eight_seven

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

16 minutes ago, rkit said:

std::function

Не во всех проектах допустимо применение std, раскройте его реализацию ради интереса, это как раз и есть делегат. Вот тут в комментах неплохо расписано про его "особенности".

Минус std один - по делу и без дела увлекается дин. памятью ((

 

Пример выше кстати соберется на C++11 и выше (из-за лямбд), не мой пример, но там показаны разные способы применения.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

8 минут назад, one_eight_seven сказал:

Потому и спрашиваю - вам ООП или процедурный подход?

Ну не знаю я сейчас, насколько оптимален будет подход ООП. Обычно подход ООП подразумевает раздутие накладных на ровном месте.
Я примерно представляю, какие накладные будут в callback-ах, и не представляю, какие будут при всех этих наследованиях от всяких абстракций и т.д.

P.S. Сергей, спасибо за ссылку. Я внимательно изучу, как домой приду. Сходу тяжело "въехать" что там за конструкции такие страшные.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

2 minutes ago, Arlleex said:

какие будут при всех этих наследованиях от всяких абстракций и т.д.

Они сокращают сложность и улучшают сопровождаемость кода из-за необходимости работы над предварительной проработкой структуры проекта, иначе этот ООП скорее навредит.

Это как дай бензопилу тому, кто только ножовкой работал, так тот может себе конечности отрезать ))

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 минуту назад, Forger сказал:

Это как дай бензопилу тому, кто только ножовкой работал, так тот может себе конечности отрезать ))

Я понимаю... Но тогда, если так рассуждать, то как "ножовочнику" научиться играть на бензопиле?:wink:

А тем не менее, я еще ни одного проекта за свою практику не увидел от гуру плюсов (у нас на работе, например), чтобы хотя бы элементарный принцип "класс работы с протоколом написал - и таскаешь из проекта в проект" соблюдался - вечно допиливается, вечно адаптируется, и хрен бы с ним в одном месте - да нет же, в куче мест в исходниках. Но я пока еще верю, что всякие прикладные вещи можно написать так, чтобы таскать .cpp/.hpp-пару из проекта в проект, не модифицируя в них ничего. Это просто к слову. Еще ни в одной книжке по плюсам я не увидел плюсов и минусов того или иного способа забить гвоздь. Просто описание в стиле "ну можно вот так, а можно вот так - все это есть в C++". Круто, ага. Потом сел, открыл дизасм и волосы дыбом.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...