Полиморфизм в классах смешивания — виртуальные функции

В настоящее время я читаю о классах миксина и думаю, что понимаю все более или менее. Единственное, чего я не понимаю, это почему мне больше не нужны виртуальные функции. (Увидеть Вот а также Вот)

Например. великий волк пишет в его ответ здесь что виртуальные функции не нужны. Вот пример: (Я просто скопировал основные части)

struct Number
{
typedef int value_type;
int n;
void set(int v) { n = v; }
int get() const { return n; }
};

template <typename BASE, typename T = typename BASE::value_type>
struct Undoable : public BASE
{
typedef T value_type;
T before;
void set(T v) { before = BASE::get(); BASE::set(v); }
void undo() { BASE::set(before); }
};

typedef Undoable<Number> UndoableNumber;

int main()
{
UndoableNumber mynum;
mynum.set(42); mynum.set(84);
cout << mynum.get() << '\n';  // 84
mynum.undo();
cout << mynum.get() << '\n';  // 42
}

Но что теперь будет, если я сделаю что-то вроде этого:

void foo(Number *n)
{
n->set(84);    //Which function is called here?
}

int main()
{
UndoableNumber mynum;
mynum.set(42);
foo(&mynum);
mynum.undo();
cout << mynum.get() << '\n';  // 42 ???
}

Какое значение имеет mynum и почему? Работает ли полиморфизм в foo()?!?

0

Решение

n-> набор (84); // Какая функция здесь вызывается?

Number::set будет называться здесь.

Работает ли полиморфизм в foo ()?!?

Нет, без virtual, Если вы попробуете код, вы получите неопределенное значение, потому что before не устанавливается вообще.

ЖИТЬ

0

Другие решения

Я скомпилировал ваш код в VS 2013, и он дает неуказанное число.

У вас нет конструктора в вашей структуре, что означает, что переменная before не инициализирована.

0

Ваш пример кода вызывает неопределенное поведение, потому что вы пытаетесь читать из int переменная n пока он не находится в действительном состоянии. Вопрос не в том, какое значение будет напечатано. Ваша программа не обязана печатать что-либо или делать что-либо, что имеет смысл, хотя вы, вероятно, используете машину, на которой неопределенное поведение будет отображаться как случайное значение n или на котором он в основном будет отображаться как 0.

Ваш компилятор, вероятно, даст вам важный совет, если вы позволите ему обнаруживать такие проблемы, например:

34:21: warning: 'mynum.Number::n' is used uninitialized in this function [-Wuninitialized]

Однако неопределенное поведение начинается еще до этого. Вот как это происходит, шаг за шагом:

UndoableNumber mynum;

Это также создает Number подобъект с unintialised n. Тот n имеет тип int и, таким образом, его отдельные биты могут быть установлены на так называемые представление ловушки.

mynum.set(42);

Это вызывает производный класс set функция. Внутри setсделана попытка установить before переменная-член для неинициализированного n значение с возможным представлением ловушки:

void set(T v) { before = BASE::get(); BASE::set(v); }

Но вы не можете безопасно сделать это. before = BASE::get() часть уже не права, потому что Base::get() копирует int с возможным представлением ловушки. Это уже неопределенное поведение.

Это означает, что с этого момента C ++ как язык программирования больше не определяет, что произойдет. Рассуждение об остальной части вашей программы является спорным.


Все же давайте предполагать на мгновение, что копия будет в порядке. Что еще будет потом?

Base::set называется, настройка n к действительному значению. before остается в своем предыдущем недействительном статусе.

Сейчас foo называется:

void foo(Number *n)
{
n->set(84);    //Which function is called here?
}

база-учебный класс set называется потому что n имеет тип Number* а также set является невиртуальном.

set счастливо устанавливает n переменная-член до 84. Производный класс before остается недействительным.

Теперь undo Функция вызывается и выполняет следующие действия:

BASE::set(before);

После этого назначения, n больше не 84, но установлено недействительным before значение.

И наконец…

cout << mynum.get() << '\n';

get возвращает неверное значение. Вы пытаетесь распечатать его. Это даст неуказанные результаты даже на машине, у которой нет представления ловушек для ints (вы, скорее всего, используете такую ​​машину).


Заключение:

  • C ++ как язык не определяет, что делает ваша программа. Он может что-то печатать, ничего не печатать, аварийно завершать работу или делать то, что ему нравится, все потому, что вы копируете int,

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

  • Если вы хотите, чтобы ваш производный класс set быть вызванным при вызове на Number*тогда вы должны сделать set virtual функция в Number,

0
По вопросам рекламы [email protected]