Вызов виртуального метода из базы

Я пытаюсь создать библиотеку для MigraDoc на основе этого примера, который поддерживает различные типы документов. Моя идея состояла в том, чтобы создать базовый класс с виртуальным методом для CreatePage() (метод, отвечающий за макет страницы). Однако концепция заключалась в том, что CreatePage() следует вызывать из метода с именем CreateDocument(), который вызывается пользователем. Увы, CreatePage() можно будет переопределить, но он не предназначен для прямого вызова. Это будет выглядеть примерно так:

public class DocumentWriter
{
    private Document document;

    public virtual void CreateDocument(IDocumentArgs args)
    {
       document = new Document();

       DefineStyles();
       CreatePage();
       FillContent(args);
    }

    public virtual void CreatePage()
    {
        // Create page layout here
    }

    // Remaining code skipped for readability...
}

Но если создать унаследованный класс, который переопределяет CreatePage(), то какой метод будет вызываться из CreateDocument()?

  • Оригинальный виртуальный (не переопределенный) метод
  • Метод, который переопределяет CreatePage()

person Jakob Busk Sørensen    schedule 20.06.2018    source источник
comment
Переопределение будет вызвано.   -  person Llama    schedule 20.06.2018
comment
если вы затем создаете экземпляр производных классов и вызываете CreateDocument, он будет вызывать только переопределенный метод   -  person Amit    schedule 20.06.2018
comment
если вы не хотите вызывать CreatePage() напрямую из другого кода, вы можете использовать модификатор protected   -  person rum    schedule 20.06.2018
comment
В этом весь смысл ovderride, чтобы иметь возможность перезаписать базовую реализацию. В любом случае вы можете просто попробовать это сами, написав тестовую программу с некоторым виртуальным членом и проверив, какой член вызывается, когда вы переопределяете его в своем классе.   -  person HimBromBeere    schedule 20.06.2018
comment
для такого подхода используйте шаблон проектирования шаблона с абстрактным классом, где метод останется абстрактным   -  person Pranay Rana    schedule 20.06.2018
comment
@PranayRana именно это я и сделал. Поэтому я рад видеть, что это предложил кто-то другой :-).   -  person Jakob Busk Sørensen    schedule 20.06.2018
comment
@Noceo - я собирался ответить, но потом вижу, что вы приняли ответ и довольны им, поэтому не ответили   -  person Pranay Rana    schedule 20.06.2018


Ответы (1)


Поскольку метод virtual, будет вызвана правильная версия. Работающий механизм называется полиморфизм.

На самом деле CreateDocument даже не обязательно должен быть виртуальным, чтобы это работало (если только вы не собираетесь переопределять его в другом базовом классе).

Вы можете увидеть это в работе с простой тестовой программой (обратите внимание, что я сделал CreatePage protected, так что это не может быть вызывается извне DocumentWriter или его базовых классов). Обратите внимание, что даже когда я вызываю CreateDocument явно через тип базового класса, он всегда будет вызывать правильную версию на основе типа объекта во время выполнения.

public class DocumentWriter
{
    public /*virtual*/ void CreateDocument()
    {
       CreatePage();
    }

    protected virtual void CreatePage()
    {
        System.Console.WriteLine("DocumentWriter.CreatePage()");
    }
}

public class PdfDocumentWriter : DocumentWriter
{
    protected override void CreatePage()
    {
        System.Console.WriteLine("PdfDocumentWriter.CreatePage()");
    }
}

public class HtmlDocumentWriter : DocumentWriter
{
    protected override void CreatePage()
    {
        System.Console.WriteLine("HtmlDocumentWriter.CreatePage()");
    }
}

public static class Program
{
    public static void Main()
    {
        DocumentWriter documentWriter = new PdfDocumentWriter();
        documentWriter.CreateDocument();

        // Re-use the same variable. 
        // CreateDocumentwill still call the correct version of CreatePage.
        documentWriter = new HtmlDocumentWriter();
        documentWriter.CreateDocument();
    }
}

Это печатает

PdfDocumentWriter.CreatePage()
HtmlDocumentWriter.CreatePage()

как и ожидалось.

person CompuChip    schedule 20.06.2018
comment
Спасибо за очень понятный ответ. Я сделаю базовую функцию невиртуальной (поскольку ее нельзя переопределять) и позволю переопределять только подметоды. - person Jakob Busk Sørensen; 20.06.2018