2010-08-23 3 views
5

У меня есть некоторые сомнения при сравнении множественного наследования C++ и Java.C++ и Java: использование виртуального базового класса

  1. Даже Java использует несколько, многоуровневое наследование через интерфейсы - но почему оленья кожа это использовать что-то вроде виртуального базового класса, как и в C++? Это потому, что членам java-интерфейса обеспечивается одна копия в памяти (они являются публичными статическими окончательными), а методы только объявлены и не определены?

  2. Помимо сохранения памяти, есть ли другое использование виртуальных классов в C++? Есть ли какие-либо оговорки, если я забуду использовать эту функцию в своих программах множественного наследования?

  3. Этот вопрос немного философский - но почему разработчики C++ не сделали его по умолчанию, чтобы сделать каждый базовый класс виртуальным? Какая потребность в обеспечении гибкости?

Примеры будут оценены. Благодаря !!

+0

Что вы подразумеваете под «виртуальным базовым классом» в C++? Класс, который имеет хотя бы одну чистую виртуальную функцию (например, virtual void booga() = 0;)? – FireAphis

+1

@FireAphis: http://publib.boulder.ibm.com/infocenter/comphelp/v7v91/index.jsp?topic=/com.ibm.vacpp7a.doc/language/ref/clrc14cplr135.htm – SlowAndSteady

+0

Базовый класс с по крайней мере одна виртуальная функция (не обязательно чистая виртуальная функция) является виртуальным базовым классом. Базовый класс с хотя бы одной чистой виртуальной функцией называется абстрактным базовым классом. –

ответ

3

1) Интерфейсы Java не имеют атрибутов. Одной из причин виртуальных базовых классов в C++ является предотвращение дублирования атрибутов и всех связанных с этим трудностей.

2) Для использования виртуальных базовых классов в C++ существует хотя бы небольшое ограничение производительности. Кроме того, конструкторы становятся настолько сложными, что рекомендуется, чтобы виртуальные базовые классы не имели конструкторов без аргументов.

3) Именно из-за C++ philosphy: не нужно требовать штрафа за то, что вам может не понадобиться.

3
  1. Извините, не программист на Java, поэтому кратко о деталях. Тем не менее, виртуальные базы - это усовершенствование множественного наследования, которое разработчики Java всегда защищали от омминга на том основании, что он слишком сложный и, возможно, подверженный ошибкам.

  2. виртуальные базы предназначены не только для сохранения памяти - данные разделяются между различными объектами, наследуемыми от них, поэтому эти производные типы могут использовать его для координации своего поведения. Они часто не так полезны, но в качестве примера: идентификаторы объектов, в которых вы хотите получить один идентификатор для большинства производных объектов, а не считать все подобъекты. Еще один пример: обеспечение того, что многократно производный тип может однозначно отображать/преобразовываться в указатель на базу, сохраняя его легкостью в функциях, работающих на базовом типе, или для хранения в контейнерах Base *.

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

2

1. Ява множественное наследование в интерфейсах ведет себя как виртуальное наследование в C++. Точнее, для реализации java-подобной модели наследования в C++ вам нужно использовать виртуальные базовые классы C++.

Однако один из недостатков C++ виртуального inheriritance (за исключением небольшой памяти и потери производительности) является невозможность static_cast <> от основания к производным, таким RTTI (dynamic_cast) должны быть использованы (или один может обеспечить «ручной» виртуальные функции литейные для дочерних классов, если список таких дочерних классов известны заранее)

2.Если вы забыли «виртуальный» спецификатор в списке наследования, как правило, приводит к ошибке компилятора поскольку любое литье frome drived to base class становится неоднозначным

3.Философский q uestions, как правило, довольно далеки от ответа ... C++ - это многопартийный (и многофилософский) язык и не навязывает каких-либо философских решений. Вы можете использовать виртуальное наследование, когда это возможно, в ваших собственных проектах, и (вы rioght) у него есть веская причина. Но такие максимумы могут быть неприемлемыми для других, поэтому универсальные инструменты C++ (стандартные и другие широко используемые библиотеки) должны быть (если возможно) свободными от каких-либо конкретных философских соглашений.

1

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

Дело в том, что я написал статью, в которой показано, как вы можете обойти стирание стилей в Java. В статье хорошо объясняется, как это можно сделать, и в конце концов, как ваш исходный код может в конце концов очень похож на C++.

http://www.jquantlib.org/index.php/Using_TypeTokens_to_retrieve_generic_parameters

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

В случае, если у вас есть интерес к такому черному волшебству, приведенные ниже строки могут быть полезны для вас как-то. В противном случае, конечно, нет.

Хорошо. Вперед.

В Java существует несколько трудностей: 1. Тип стирания (решена в статье) 2. javac не был предназначен для понимания того, что такое виртуальный базовый класс; 3. Даже используя трюки, вы не сможете обойти трудность №2, потому что эта сложность появляется во время компиляции.

Если вы хотите использовать виртуальные базовые классы, вы можете получить его с помощью Scala, который в основном решил трудность №2, точно создав другой компилятор, который, я бы сказал, полностью понимает некоторые более сложные объектные модели.

, если вы хотите, чтобы изучить мою статью и попытаться «circunvent» виртуальных базовых классов в чистом Java (не Scala), вы могли бы сделать что-то, как я объясню ниже:

Предположим, что у вас есть что-то вроде этого в C++:

template<Base> 
public class Extended : Base { ... } 

это может быть перевести на что-то вроде этого в Java:

public interface Virtual<T> { ... } 

public class Extended<B> implements Virtual<B> { ... } 

OK. Что происходит, когда вы создаете экземпляр Extended, как показано ниже?

Extended extended = new Extended<Base>() { /* required anonymous block here */ } 

Ну .. в основном вы будете в состоянии избавиться от типа стирания и будет иметь возможность получить информацию о типе базы внутри вашего класса Extended. См. Мою статью для подробного объяснения черной магии.

OK. Когда у вас есть тип Base in Extended, вы можете создать конкретную реализацию Virtual.

Обратите внимание, что во время компиляции, Javac может проверить типы для вас, как в примере ниже:

public interface Virtual<Base> { 
    public List<Base> getList(); 
} 

public class Extended<Base> implements Virtual<Base> { 
    @Override 
    public List<Base> getList() { 
     // TODO Auto-generated method stub 
     return null; 
    } 
} 

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

Надеюсь, это поможет ... если не смутить вас!

Смежные вопросы