Почему там диграфы в C и C++?

С помощью вы можете обрабатывать ссылку на интерфейс как одну вверху в иерархии.

С помощью вы можете обрабатывать ссылку на интерфейс как одну вниз в hiearchy.

Позвольте мне объяснить это на более английском языке.

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

Итак, с вашим списком животных (который содержит животных разных типов), вы может сказать, что у всех животных есть имя, поэтому, очевидно, было бы безопасно получить имя всех животных.

Однако, если у вас есть только список рыб, но вам нужно относиться к ним как к животные, это работает? Интуитивно, он должен работать, но в C # 3.0 и ранее этот фрагмент кода не будет компилироваться:

IEnumerable animals = GetFishes(); // returns IEnumerable

Причиной этого является то, что компилятор не «знает», что вы намерены, или может , делать с коллекцией животных после того, как вы ее извлекли. Для всех, кто знает, может существовать путь через IEnumerable, чтобы вернуть объект в список, и это потенциально позволит вам помещать животное, которое не является рыбой, в коллекцию, которая должна содержать только рыбу .

Другими словами, компилятор не может гарантировать, что это недопустимо:

animals.Add(new Mammal("Zebra"));

Таким образом, компилятор просто отказывается компилировать ваш код. Это ковариация.

Давайте посмотрим на контравариантность.

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

В C # 3.0 и ранее это не компилируется:

List fishes = GetAccessToFishes(); // for some reason, returns List
fishes.Add(new Fish("Guppy"));

Здесь компилятор мог разрешить эту часть кода, даже если метод возвращает List просто потому, что все рыбы являются животными, поэтому, если мы просто изменили типы на это:

List fishes = GetAccessToFishes();
fishes.Add(new Fish("Guppy"));

Тогда это сработает, но компилятор не может определить, что вы не пытаетесь это сделать:

List fishes = GetAccessToFishes(); // for some reason, returns List
Fish firstFist = fishes[0];

Поскольку список на самом деле является списком животных, это не разрешено.

Таким образом, противоречие и коразмерность - это то, как вы обрабатываете ссылки на объекты и что вам разрешено с ними.

Ключевые слова in и out в C # 4.0 специально маркируют интерфейс как тот или другой. С помощью in вы можете поместить общий тип (обычно T) в input -позиции, что означает аргументы метода и свойства только для записи.

С помощью out, вы можете поместить общий тип в output -позиции, которые являются значениями возврата метода, свойствами только для чтения и параметрами метода out.

Это позволит вы делаете то, что намерено делать с кодом:

IEnumerable animals = GetFishes(); // returns IEnumerable
// since we can only get animals *out* of the collection, every fish is an animal
// so this is safe

List имеет как входы, так и выходы на T, поэтому он не является ни ковариантным, ни контравариантным, но интерфейс что позволило вам добавлять объекты, например:

interface IWriteOnlyList
{
    void Add(T value);
}

позволит вам сделать это:

IWriteOnlyList fishes = GetWriteAccessToAnimals(); // still returns
                                                            IWriteOnlyList
fishes.Add(new Fish("Guppy")); <-- this is now safe

Вот несколько видеороликов, которые показывают понятия:

Вот пример:

namespace SO2719954
{
    class Base { }
    class Descendant : Base { }

    interface IBibbleOut { }
    interface IBibbleIn { }

    class Program
    {
        static void Main(string[] args)
        {
            // We can do this since every Descendant is also a Base
            // and there is no chance we can put Base objects into
            // the returned object, since T is "out"
            // We can not, however, put Base objects into b, since all
            // Base objects might not be Descendant.
            IBibbleOut b = GetOutDescendant();

            // We can do this since every Descendant is also a Base
            // and we can now put Descendant objects into Base
            // We can not, however, retrieve Descendant objects out
            // of d, since all Base objects might not be Descendant
            IBibbleIn d = GetInBase();
        }

        static IBibbleOut GetOutDescendant()
        {
            return null;
        }

        static IBibbleIn GetInBase()
        {
            return null;
        }
    }
}

Без эти метки могут составить следующее:

public List GetDescendants() ...
List bases = GetDescendants();
bases.Add(new Base()); <-- uh-oh, we try to add a Base to a Descendant

или это:

public List GetBases() ...
List descendants = GetBases(); <-- uh-oh, we try to treat all Bases
                                               as Descendants

71
задан Sydius 11 January 2009 в 06:07
поделиться

3 ответа

Диграфы были созданы для программистов, которые не имели клавиатуры, которая поддерживала набор символов ISO 646.

http://en.wikipedia.org/wiki/C_trigraph

60
ответ дан CTT 7 November 2019 в 08:59
поделиться

Я полагаю, что их существование может быть прослежено до возможность , что где-нибудь, кто-то использует компилятор с операционной системой, набор символов которой так архаичен, что это не обязательно имеет все символы, что C или C++ должны выразить целый язык.

кроме того, это делает для хороших записей в IOCCC.

24
ответ дан Greg Hewgill 7 November 2019 в 08:59
поделиться

Я думаю, что это - потому что некоторые клавиатуры на этой планете не могли бы иметь ключей как '#' и '{'.

12
ответ дан ChrisW 7 November 2019 в 08:59
поделиться