Как этот C кодирует работу?

Перекрестные типы позволяют, Вы к (своего рода вид) делаете перечисления, которые имеют иерархию наследования. Вы не можете наследовать реализацию, но можно делегировать ее к классу помощника.

enum Foo1 implements Bar {}
enum Foo2 implements Bar {}

class HelperClass {
   static <T extends Enum<T> & Bar> void fooBar(T the enum) {}
}

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

enum PrimaryColor {Red, Green, Blue;}
enum PastelColor {Pink, HotPink, Rockmelon, SkyBlue, BabyBlue;}

enum TransportMedium {Land, Sea, Air;}
enum Vehicle {Car, Truck, BigBoat, LittleBoat, JetFighter, HotAirBaloon;}

можно ли записать общие методы, которые говорят "Хорошо, учитывая перечисление значений, это - родитель некоторых других перечислимых значений, какой процент всех возможных дочерних перечислений дочернего типа имеют это конкретное родительское значение как их родителя?", и имейте все это безопасное с точки зрения типов и обошедшееся без кастинг. (например: то "Море" составляет 33% всех возможных механизмов и "Зеленые" 20% всех возможных Пастелей).

код похожи на это. Это довольно противно, но существуют способы сделать его лучше. Обратите внимание в particuar, что сами "листовые" классы довольно аккуратны - универсальные классы имеют объявления, которые ужасно ужасны, но Вы только пишете им onece. После того как универсальные классы там, затем используют их, легко.

import java.util.EnumSet;

import javax.swing.JComponent;

public class zz extends JComponent {

    public static void main(String[] args) {
        System.out.println(PrimaryColor.Green + " " + ParentUtil.pctOf(PrimaryColor.Green) + "%");
        System.out.println(TransportMedium.Air + " " + ParentUtil.pctOf(TransportMedium.Air) + "%");
    }


}

class ParentUtil {
    private ParentUtil(){}
    static <P extends Enum<P> & Parent<P, C>, C extends Enum<C> & Child<P, C>> //
    float pctOf(P parent) {
        return (float) parent.getChildren().size() / //
                (float) EnumSet.allOf(parent.getChildClass()).size() //
                * 100f;
    }
    public static <P extends Enum<P> & Parent<P, C>, C extends Enum<C> & Child<P, C>> //
    EnumSet<C> loadChildrenOf(P p) {
        EnumSet<C> cc = EnumSet.noneOf(p.getChildClass());
        for(C c: EnumSet.allOf(p.getChildClass())) {
            if(c.getParent() == p) {
                cc.add(c);
            }
        }
        return cc;
    }
}

interface Parent<P extends Enum<P> & Parent<P, C>, C extends Enum<C> & Child<P, C>> {
    Class<C> getChildClass();

    EnumSet<C> getChildren();
}

interface Child<P extends Enum<P> & Parent<P, C>, C extends Enum<C> & Child<P, C>> {
    Class<P> getParentClass();

    P getParent();
}

enum PrimaryColor implements Parent<PrimaryColor, PastelColor> {
    Red, Green, Blue;

    private EnumSet<PastelColor>    children;

    public Class<PastelColor> getChildClass() {
        return PastelColor.class;
    }

    public EnumSet<PastelColor> getChildren() {
        if(children == null) children=ParentUtil.loadChildrenOf(this);
        return children;
    }
}

enum PastelColor implements Child<PrimaryColor, PastelColor> {
    Pink(PrimaryColor.Red), HotPink(PrimaryColor.Red), //
    Rockmelon(PrimaryColor.Green), //
    SkyBlue(PrimaryColor.Blue), BabyBlue(PrimaryColor.Blue);

    final PrimaryColor  parent;

    private PastelColor(PrimaryColor parent) {
        this.parent = parent;
    }

    public Class<PrimaryColor> getParentClass() {
        return PrimaryColor.class;
    }

    public PrimaryColor getParent() {
        return parent;
    }
}

enum TransportMedium implements Parent<TransportMedium, Vehicle> {
    Land, Sea, Air;

    private EnumSet<Vehicle>    children;

    public Class<Vehicle> getChildClass() {
        return Vehicle.class;
    }

    public EnumSet<Vehicle> getChildren() {
        if(children == null) children=ParentUtil.loadChildrenOf(this);
        return children;
    }
}

enum Vehicle implements Child<TransportMedium, Vehicle> {
    Car(TransportMedium.Land), Truck(TransportMedium.Land), //
    BigBoat(TransportMedium.Sea), LittleBoat(TransportMedium.Sea), //
    JetFighter(TransportMedium.Air), HotAirBaloon(TransportMedium.Air);

    private final TransportMedium   parent;

    private Vehicle(TransportMedium parent) {
        this.parent = parent;
    }

    public Class<TransportMedium> getParentClass() {
        return TransportMedium.class;
    }

    public TransportMedium getParent() {
        return parent;
    }
}
6
задан Brian Tompsett - 汤莱恩 18 February 2016 в 11:50
поделиться

7 ответов

## объединяет два токена вместе. Его можно использовать только в препроцессоре.

f (1,2) становится 1 ## 2 становится 12 .

Сам по себе оператор # преобразует токенов в строку: #a становится «a» . Следовательно, g (f (1,2)) становится «f (1,2)» , когда препроцессор завершает работу с ним.

h (f (1,2) )) фактически # (1 ## 2) , который становится # 12 , который становится "12" , когда препроцессор работает над ним.

19
ответ дан 8 December 2019 в 03:01
поделиться

По таким вопросам (а также к другим «реальным» проблемам, связанным с препроцессором), я считаю очень полезным прочитать код, после он был предварительно обработан.

Как это сделать зависит от компилятора, но с gcc вы должны использовать это:

$ gcc -E test.c

(snip)
main()
{
        printf("%s\n","12");
        printf("%s\n","f(1,2)");
}

Итак, вы можете видеть, что символы были объединены и преобразованы в строку.

5
ответ дан 8 December 2019 в 03:01
поделиться

Макрос f (a, b) объединяет свои аргументы, g (a) превращает свои аргументы в строку, а h (a) является вспомогательным макросом для g (a). Я думаю, он выведет:

12
f(1,2)

Причина в том, что макрос h (a) вызывает полное раскрытие своего аргумента перед передачей его в g (a), тогда как g (a) принимает свои аргументы буквально, не раскрывая их предварительно.

3
ответ дан 8 December 2019 в 03:01
поделиться

a##b will paste the code togather.

so f(1,2) will become 12

4
ответ дан 8 December 2019 в 03:01
поделиться

a ## b - это строковое соединение литералов a и b, поэтому f (1,2) равно "12"

#a - это строковый литерал a, поэтому g (3 ) равно "3"

0
ответ дан 8 December 2019 в 03:01
поделиться

## - это оператор конкатенации макросов. Так, например, f (foo,

0
ответ дан 8 December 2019 в 03:01
поделиться
  #define f(a,b) a##b
  #define g(a)   #a
  #define h(a) g(a)

Итак, ## объединяет две части напрямую, независимо от того, какого они типа являются... Приведу пример .. printf ("% d \ n", f (1,2)); вы получите 12, это означает, что здесь f (1,2) равно 12 целому числу.

    int a2 = 100;
    printf("%d\n",f(a,2));

здесь f (a, 2 ) это метка. он указывает на метку в контексте вашего кода, если нет int a2 = 100 , вы получите ошибки компиляции. И #a превращает все, что есть, в строку ... А затем h (a) g (a) Это очень странно .. Похоже, что когда вы вызываете h (a), он превращается в g (a) и передает a в g (a), во-первых, он интерпретирует, что такое a. Итак, прежде чем вы сможете g (a), a преобразуется в f (a, b) = a ## b = 12

0
ответ дан 8 December 2019 в 03:01
поделиться
Другие вопросы по тегам:

Похожие вопросы: