AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / coding / Perguntas / 79562550
Accepted
Stef1611
Stef1611
Asked: 2025-04-09 00:03:15 +0800 CST2025-04-09 00:03:15 +0800 CST 2025-04-09 00:03:15 +0800 CST

Sobrecarga de procedimento com uma variável alocável como parâmetro em fortran

  • 772

Estou aprendendo POO em Fortran. E me pergunto sobre o interesse de sobrecarregar procedimentos com limite de tipo quando o tipo de um argumento não é conhecido em tempo de compilação.

Deixe-me explicar, passo a passo, meu problema (Esses programas são apenas exemplos para aumentar minha habilidade em fortran)

Primeiro programa: sobrecarga de um procedimento de tipo limitado

module my_mod

  implicit none
  
  type :: my_type_t
    character(len=128) :: my_text
  contains
    procedure :: integer_print, real_print
    generic :: my_print => integer_print, real_print
  end type my_type_t
  
  contains
  
  subroutine integer_print(this, my_int)
    class(my_type_t), intent(in) :: this
    integer, intent(in) :: my_int
    write (*,"(a,a,i0)") trim(this%my_text),' integer ', my_int
  end subroutine integer_print
  
  subroutine real_print(this, my_real)
    class(my_type_t), intent(in) :: this
    real, intent(in) :: my_real
    write (*,"(a,a,f0.3)") trim(this%my_text),' real ', my_real
  end subroutine real_print

end module my_mod

program my_pgm

  use my_mod
  implicit none
  
  type(my_type_t) :: my_var
  my_var%my_text = "Hello"
  
  call my_var%my_print(10)
  call my_var%my_print(9.9)

end program my_pgm

Deu o resultado esperado. Ou integer_printou real_printé usado, dependendo do tipo de my_printargumento (inteiro ou real).

Segundo programa (ou passo, eu diria): um tipo abstrato é usado e há dois tipos derivados: my_int_te my_real_t. É muito semelhante ao primeiro exemplo. Mas, dois tipos são usados, um para inteiros e outro para reais.

module my_mod

  implicit none
  
  type, abstract :: my_abstract_t
  end type  my_abstract_t
  
  type, extends(my_abstract_t) :: my_int_t
    integer :: an_integer
  end type my_int_t
  
  type, extends(my_abstract_t) :: my_real_t
    real :: a_real
  end type my_real_t
  
  type :: my_type_t
    character(len=128) :: my_text
  contains
    procedure :: integer_print, real_print
    generic :: my_print => integer_print, real_print
  end type my_type_t
  
  contains
  
  subroutine integer_print(this, my_int)
    class(my_type_t), intent(in) :: this
    type(my_int_t), intent(in) :: my_int
    write (*,"(a,a,i0)") trim(this%my_text),' integer ', my_int%an_integer
  end subroutine integer_print
  
  subroutine real_print(this, my_real)
    class(my_type_t), intent(in) :: this
    type(my_real_t), intent(in) :: my_real
    write (*,"(a,a,f0.3)") trim(this%my_text),' real ', my_real%a_real
  end subroutine real_print

end module my_mod

program my_pgm

  use my_mod
  implicit none
  
  type(my_type_t) :: my_var
  type(my_int_t) :: my_int
  type(my_real_t) :: my_real
  
  my_var%my_text = "Hello"
  
  my_int%an_integer = 10
  my_real%a_real = 9.9
  
  call my_var%my_print(my_int)
  call my_var%my_print(my_real)

end program my_pgm

O tipo de my_intand my_realé conhecido no momento da compilação, portanto a saída está correta. E a mesma chamada my_var%my_print(...)é usada independentemente do tipo da variável ( my_int_tor my_real_t), como no primeiro exemplo.

Mas agora esse é o meu problema.

program my_pgm

  use my_mod
  implicit none
  
  type(my_type_t) :: my_var
  class(my_abstract_t), allocatable :: my_number
  
  allocate(my_int_t::my_number)
  ! or allocate(my_real_t::my_number)
  
  my_var%my_text = "Hello"

  select type (my_number)
  type is (my_int_t)
      my_number%an_integer = 10
  type is (my_real_t)
      my_number%a_real = 9.9
  end select
  
  select type (my_number)
  type is (my_int_t)
      call my_var%my_print(my_number)
  type is (my_real_t)
      call my_var%my_print(my_number)
  end select

end program my_pgm

O tipo de my_numbernão é conhecido em tempo de compilação. Então, preciso usar um trecho de código que achei bastante redundante:

  select type (my_number)
  type is (my_int_t)
      call my_var%my_print(my_number)
  type is (my_real_t)
      call my_var%my_print(my_number)
  end select

Eu teria preferido escrever apenas uma linha: call my_var%my_print(...)como no primeiro e no segundo exemplos. Devo concluir que a sobrecarga de procedimento não tem interesse no terceiro exemplo e é melhor usar integer_printe real_printdiretamente no select typebloco? Ou há algo que eu não entendi?

Edição 1

Seguindo os comentários de Francescalus, se entendi bem, não consegui evitar o select typebloqueio. Então, modifiquei o programa da seguinte maneira.

module my_mod

  implicit none
  
  type, abstract :: my_abstract_t
  end type  my_abstract_t
  
  type, extends(my_abstract_t) :: my_int_t
    integer :: an_integer
  end type my_int_t
  
  type, extends(my_abstract_t) :: my_real_t
    real :: a_real
  end type my_real_t
  
  type :: my_type_t
    character(len=128) :: my_text
  contains
    procedure, private :: real_print, integer_print
    procedure, public :: my_print
  end type my_type_t
  
  contains
  
  subroutine integer_print(this, my_int)
    class(my_type_t), intent(in) :: this
    type(my_int_t), intent(in) :: my_int
    write (*,"(a,a,i0)") trim(this%my_text),' integer ', my_int%an_integer
  end subroutine integer_print
  
  subroutine real_print(this, my_real)
    class(my_type_t), intent(in) :: this
    type(my_real_t), intent(in) :: my_real
    write (*,"(a,a,f0.3)") trim(this%my_text),' real ', my_real%a_real
  end subroutine real_print
  
  subroutine my_print(this,my_number)
    class(my_type_t), intent(in) :: this
    class(my_abstract_t), intent(in) :: my_number
    
    select type (my_number)
    type is (my_int_t)
        call this%integer_print(my_number)
    type is (my_real_t)
        call this%real_print(my_number)
    end select
    
  end subroutine my_print
    

end module my_mod

program my_pgm

  use my_mod
  implicit none
  
  type(my_type_t) :: my_var
  class(my_abstract_t), allocatable :: my_number1, my_number2
  
  my_number1 = my_int_t(an_integer = 10)
  my_number2 = my_real_t(a_real = 9.9)
  
  my_var%my_text = "Hello"

  call my_var%my_print(my_number1)
  call my_var%my_print(my_number2)
  
end program my_pgm

Qualquer comentário será apreciado.

oop
  • 1 1 respostas
  • 58 Views

1 respostas

  • Voted
  1. Best Answer
    Vladimir F Героям слав
    2025-04-09T17:26:02+08:002025-04-09T17:26:02+08:00

    Pode-se usar despacho duplo , também chamado de padrão de visitante.

    Esta é uma implementação de exemplo para o seu código. Ela tem a limitação óbvia de que o my_type_ttipo já precisa ser conhecido. No entanto, o uso de select_typeé evitado e outros tipos de extensão my_abstract_typepodem ser adicionados livremente.

    module my_mod
    
      implicit none
      
    
      type :: my_type_t
        character(len=128) :: my_text
      contains
        procedure, public :: my_print
      end type my_type_t
    
      type, abstract :: my_abstract_t
      contains
        procedure(get_printed_from_my_type_t_interface), deferred :: get_printed_from_my_type_t
      end type  my_abstract_t
    
      abstract interface
        subroutine get_printed_from_my_type_t_interface(this, printer)
          import
          class(my_abstract_t), intent(in) :: this
          type(my_type_t), intent(in) :: printer
        end subroutine
      end interface
      
      
      type, extends(my_abstract_t) :: my_int_t
        integer :: an_integer
      contains
        procedure :: get_printed_from_my_type_t => integer_print   
      end type my_int_t
      
      type, extends(my_abstract_t) :: my_real_t
        real :: a_real
      contains
        procedure :: get_printed_from_my_type_t => real_print
      end type my_real_t
      
    
      contains
      
      subroutine integer_print(this, printer)
        class(my_int_t), intent(in) :: this
        type(my_type_t), intent(in) :: printer
        write (*,"(a,a,i0)") trim(printer%my_text),' integer ', this%an_integer
      end subroutine integer_print
      
      subroutine real_print(this, printer)
        class(my_real_t), intent(in) :: this
        type(my_type_t), intent(in) :: printer
        write (*,"(a,a,f0.3)") trim(printer%my_text),' real ', this%a_real
      end subroutine real_print
      
      subroutine my_print(this,my_number)
        class(my_type_t), intent(in) :: this
        class(my_abstract_t), intent(in) :: my_number
        
        call my_number%get_printed_from_my_type_t(this)
        
      end subroutine my_print
        
    
    end module my_mod
    
    program my_pgm
    
      use my_mod
      implicit none
      
      type(my_type_t) :: my_var
      class(my_abstract_t), allocatable :: my_number1, my_number2
      
      my_number1 = my_int_t(an_integer = 10)
      my_number2 = my_real_t(a_real = 9.9)
      
      my_var%my_text = "Hello"
    
      call my_var%my_print(my_number1)
      call my_var%my_print(my_number2)
      
    end program my_pgm
    

    O ponto principal é fazer outro despacho quando type(my_type_t)já estiver disponível e mudar as implementações da impressão para os tipos individuais com os dados numéricos derivados dos my_abstract_tquais é preciso conhecer a estrutura my_type_t- isso é uma desvantagem.

    • 1

relate perguntas

  • Utilidade da propriedade de substituição do Princípio de Substituição de Liskov

  • Como o Princípio de Substituição de Liskov funciona com especialização de tipos em implementações concretas de classes abstratas?

  • Composição sobre herança - duplicação de código

  • É necessário retornar o mesmo objeto em métodos com interface fluente

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Reformatar números, inserindo separadores em posições fixas

    • 6 respostas
  • Marko Smith

    Por que os conceitos do C++20 causam erros de restrição cíclica, enquanto o SFINAE antigo não?

    • 2 respostas
  • Marko Smith

    Problema com extensão desinstalada automaticamente do VScode (tema Material)

    • 2 respostas
  • Marko Smith

    Vue 3: Erro na criação "Identificador esperado, mas encontrado 'import'" [duplicado]

    • 1 respostas
  • Marko Smith

    Qual é o propósito de `enum class` com um tipo subjacente especificado, mas sem enumeradores?

    • 1 respostas
  • Marko Smith

    Como faço para corrigir um erro MODULE_NOT_FOUND para um módulo que não importei manualmente?

    • 6 respostas
  • Marko Smith

    `(expression, lvalue) = rvalue` é uma atribuição válida em C ou C++? Por que alguns compiladores aceitam/rejeitam isso?

    • 3 respostas
  • Marko Smith

    Um programa vazio que não faz nada em C++ precisa de um heap de 204 KB, mas não em C

    • 1 respostas
  • Marko Smith

    PowerBI atualmente quebrado com BigQuery: problema de driver Simba com atualização do Windows

    • 2 respostas
  • Marko Smith

    AdMob: MobileAds.initialize() - "java.lang.Integer não pode ser convertido em java.lang.String" para alguns dispositivos

    • 1 respostas
  • Martin Hope
    Fantastic Mr Fox Somente o tipo copiável não é aceito na implementação std::vector do MSVC 2025-04-23 06:40:49 +0800 CST
  • Martin Hope
    Howard Hinnant Encontre o próximo dia da semana usando o cronógrafo 2025-04-21 08:30:25 +0800 CST
  • Martin Hope
    Fedor O inicializador de membro do construtor pode incluir a inicialização de outro membro? 2025-04-15 01:01:44 +0800 CST
  • Martin Hope
    Petr Filipský Por que os conceitos do C++20 causam erros de restrição cíclica, enquanto o SFINAE antigo não? 2025-03-23 21:39:40 +0800 CST
  • Martin Hope
    Catskul O C++20 mudou para permitir a conversão de `type(&)[N]` de matriz de limites conhecidos para `type(&)[]` de matriz de limites desconhecidos? 2025-03-04 06:57:53 +0800 CST
  • Martin Hope
    Stefan Pochmann Como/por que {2,3,10} e {x,3,10} com x=2 são ordenados de forma diferente? 2025-01-13 23:24:07 +0800 CST
  • Martin Hope
    Chad Feller O ponto e vírgula agora é opcional em condicionais bash com [[ .. ]] na versão 5.2? 2024-10-21 05:50:33 +0800 CST
  • Martin Hope
    Wrench Por que um traço duplo (--) faz com que esta cláusula MariaDB seja avaliada como verdadeira? 2024-05-05 13:37:20 +0800 CST
  • Martin Hope
    Waket Zheng Por que `dict(id=1, **{'id': 2})` às vezes gera `KeyError: 'id'` em vez de um TypeError? 2024-05-04 14:19:19 +0800 CST
  • Martin Hope
    user924 AdMob: MobileAds.initialize() - "java.lang.Integer não pode ser convertido em java.lang.String" para alguns dispositivos 2024-03-20 03:12:31 +0800 CST

Hot tag

python javascript c++ c# java typescript sql reactjs html

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve