Рассмотрим мало endian архитектур: значения сначала сохраняются в младших байтах. Таким образом, для любого заданного целого без знака значения 0-255 сохраняются в первом байте значения. Доступ к низким 8 битам любого значения просто требует указателя на его адрес.
Таким образом, мы могли бы реализовать uint8
как класс. Мы знаем, что экземпляр uint8
- это один байт. Если мы выйдем из него и создадим uint16
, uint32
и т. Д., Интерфейс останется тем же самым для целей абстракции, но самым важным изменением является размер конкретных экземпляров объекта.
Конечно, если бы мы реализовали uint8
и char
, размеры могут быть одинаковыми, аналогично sint8
.
Однако operator=
из uint8
и uint16
собираются перемещать разные количества данных.
Чтобы создать Полиморфную функцию, мы должны либо иметь возможность:
a / принять аргумент по значению, скопировав данные в новое место правильного размера и макета, b / взять указатель на местоположение объекта, c / взять ссылку на экземпляр объекта,
Мы можем использовать шаблоны для достижения a, поэтому полиморфизм может работать без указателей и ссылок, но если мы не учитываем шаблоны, тогда рассмотрим, что произойдет, если мы реализуем uint128
и передаем его функции, ожидающей uint8
? Ответ: 8 бит будут скопированы вместо 128.
Итак, если мы допустили, что наша полиморфная функция принимает uint128
, и мы передали ей uint8
. Если бы наш uint8
, который мы копировали, к сожалению, был найден, наша функция попыталась бы скопировать 128 байт, из которых 127 были за пределами нашей доступной памяти -> crash.
Рассмотрим следующее:
class A { int x; };
A fn(A a)
{
return a;
}
class B : public A {
uint64_t a, b, c;
B(int x_, uint64_t a_, uint64_t b_, uint64_t c_)
: A(x_), a(a_), b(b_), c(c_) {}
};
B b1 { 10, 1, 2, 3 };
B b2 = fn(b1);
// b2.x == 10, but a, b and c?
В момент компиляции fn
не было известно о B
. Однако B
получен из A
, поэтому полиморфизм должен позволить нам называть fn
с помощью B
. Однако возвращаемый объект должен быть A
, содержащий один int.
Если мы передадим экземпляр B
этой функции, то мы вернемся, просто { int x; }
без a, b, c.
Это «нарезка».
Даже с указателями и ссылками мы не избегаем этого бесплатно. Рассмотрим:
std::vector vec;
Элементы этого вектора могут быть указателями на A
или что-то, полученное из A
. Язык обычно решает это с помощью «vtable», небольшого дополнения к экземпляру объекта, который идентифицирует тип и предоставляет указатели на функции для виртуальных функций. Вы можете думать о нем как о чем-то вроде:
template
struct PolymorphicObject {
T::vtable* __vtptr;
T __instance;
};
Вместо каждого объекта, имеющего свой собственный vtable, классы имеют их, а экземпляры объектов просто указывают на соответствующую таблицу vtable.
Проблема теперь не нарезка, а правильность шрифта:
struct A { virtual const char* fn() { return "A"; } };
struct B : public A { virtual const char* fn() { return "B"; } };
#include
#include
int main()
{
A* a = new A();
B* b = new B();
memcpy(a, b, sizeof(A));
std::cout << "sizeof A = " << sizeof(A)
<< " a->fn(): " << a->fn() << '\n';
}
sizeof A = 4 a->fn(): B
Что мы должны иметь A
http://ideone.com/Vym3Lp
, но опять же это копирование A в A :
struct A { int i; A(int i_) : i(i_) {} virtual const char* fn() { return "A"; } };
struct B : public A {
int j;
B(int i_) : A(i_), j(i_ + 10) {}
virtual const char* fn() { return "B"; }
};
#include
#include
int main()
{
A* a = new A(1);
B* b = new B(2);
*a = *b; // aka a->operator=(static_cast(*b));
std::cout << "sizeof A = " << sizeof(A)
<< ", a->i = " << a->i << ", a->fn(): " << a->fn() << '\n';
}
(i
копируется, но B j
теряется )
. Вывод здесь состоит в том, что указатели / ссылки требуются, потому что исходный экземпляр несет с собой информацию membership , с которой может взаимодействовать копирование.
что полиморфизм не полностью решен в C ++, и нужно осознавать их обязательство предоставлять / блокировать действия, которые могут вызвать нарезку.
Это невозможно в GraphQL, однако есть экспериментальный пакет, который может быть полезен для этой цели.
https://github.com/Sydsvenskan/node-graphql-partials
См. пример:
partial LinkFields {
links(
rel: String
type: String
): [Link]
}
partial DocumentFields using LinkFields {
uuid: ID!
# The document type, such as x-im/article
type: String
# If specified, then a list of the products to which this document's availability is limited
products: [String]
# The human readable name of the document, often used publicly to identify the document
title: String
# The specific path on the web page where this document is publicly available
path: String
# A single metadata block
metaBlock(
# The specific metadata block type to get
type: String
): MetadataBlock
}
interface Document using DocumentFields {}
type AuthorDocument implements Document using DocumentFields {}
Какой приводит к:
type AuthorDocument implements Document {
links(
rel: String
type: String
): [Link]
uuid: ID!
# The document type, such as x-im/article
type: String
# If specified, then a list of the products to which this document's availability is limited
products: [String]
# The human readable name of the document, often used publicly to identify the document
title: String
# The specific path on the web page where this document is publicly available
path: String
# A single metadata block
metaBlock(
# The specific metadata block type to get
type: String
): MetadataBlock
}
То, что вы также можете сделать, поскольку это всего лишь строки, это создать некоторые вспомогательные функции, которые изменяют строку и вставляют необходимые поля.
Если вы