Я использовал этот, и он прекрасно работает для меня:
<%= link_to(line_items_path(product_id: product),
method: :put,
class: 'btn btn-success') do %>
<%= content_tag('i', nil, class: 'icon-search icon-white') %> Add To Cart
<% end %>
Надеюсь, это поможет
Следующая статья создателя C ++ описывает возможную реализацию множественного наследования:
Множественное наследование для C ++ - Бьярн Страуструп
And then, if I do a cast:
SecondBase base = (SecondBase *) object_with_base1_and_base2_parents;
The compiler must consider whether to alter or not the original pointer. Similar tricky things with virtuals.
With non-virutal inheritance this is less tricky than you might think - at the point where the cast is compiled, the compiler knows the exact layout of the derived class (after all, the compiler did the layout). Usually all that happens is a fixed offset (which may be zero for one of the base classes) is added/subtracted from the derived class pointer.
With virutal inheritance it is maybe a bit more complex - it may involve grabbing an offset from a vtbl (or similar).
Stan Lippman's book, "Inside the C++ Object Model" has very good descriptions of how this stuff might (and often actually does) work.
Была эта довольно старая статья MSDN о том, как это было реализовано в VC ++.
This is an interesting issue that really isn't C++ specific. Things get more complex also when you have a language with multiple dispatch as well as multiple inheritance (e.g. CLOS).
People have already noted that there are different ways to approach the problem. You might find reading a bit about Meta-Object Protocols (MOPs) interesting in this context...
Родители расположены в том порядке, в котором они указаны:
class Derived : A, B {} // A comes first, then B
class Derived : B, A {} // B comes first, then A
Второй случай обрабатывается в зависимости от компилятора. . Один из распространенных методов - использование указателей, размер которых превышает размер указателя платформы, для хранения дополнительных данных.
Это полностью зависит от компилятора, как это делается, но я верю, что обычно это делается с помощью иерархической структуры vtables.
Я провел простой эксперимент:
class BaseA { int a; };
class BaseB { int b; };
class Descendant : public BaseA, BaseB {};
int main() {
Descendant d;
BaseB * b = (BaseB*) &d;
Descendant *d2 = (Descendant *) b;
printf("Descendant: %p, casted BaseB: %p, casted back Descendant: %p\n", &d, b, d2);
}
Результат:
Descendant: 0xbfc0e3e0, casted BaseB: 0xbfc0e3e4, casted back Descendant: 0xbfc0e3e0
Хорошо осознавать, что статическое приведение не всегда означает «изменить тип, не затрагивая содержимое». (Ну, когда типы данных не подходят друг другу, тогда будет также вмешательство в контент, но это другая ситуация, IMO).