Определить класс C ++ в Java - PullRequest
0 голосов
/ 18 января 2011

Возможно, это не настоящий вопрос, закройте его, если он не подходит.

В C ++ нельзя смешивать заголовок и реализацию в одном исходном файле, например, класс будет определен дважды, если он включен в a.cc и b.cc:

// foo.h
#pragma once
class Foo {
    void bar() { ... }
};

// a.cc
#include "foo.h"
class A {};

// b.cc
#include "foo.h"
class B {};

// Link all
$ gcc -c -o a.o a.cc
$ gcc -c -o b.o b.cc
$ gcc -o main main.cc foo.o a.o b.o

Тогда это неоднозначно Foo :: bar () в трех объектных файлах!

Вместо этого мы должны разделить реализацию в другой файл:

// foo.h
#pragma once
class Foo {
    void bar(); 
};

// foo.cc
# include "foo.h"
void Foo::bar() { ... }

Хотя, возможно, это и не большая проблема, потому что обычно двоичные выражения для foo :: bar () в a.o и b.o совпадают. Но, по крайней мере, есть несколько лишних объявлений, не так ли? И еще некоторые беспорядки, вызванные этим избыточным:

  1. Где указать значения по умолчанию для необязательных параметров?

    class Foo {
        void bar(int x = 100); 
    };
    

    или

    void Foo::bar(int x = 100) { ... }
    

    или оба?

  2. Перемещение между встроенными и не встроенными ...?

    Если вы хотите переключить не встроенную функцию на встроенную, вы должны переместить код с foo.cc на foo.h и добавить префикс ключевого слова inline. И, может быть, через две секунды вы сожалеете о том, что сделали, затем вы перемещаете встроенный элемент в foo.h обратно в foo.cc и снова удаляете ключевое слово inline.

    Но вам не нужно будет делать это, если декларация и определение находятся вместе.

И таких мелких головных болей больше.

Идея состоит в том, что если вы напишите определение функции вместе с объявлением, то компилятор не сможет вывести прототип функции.

Например, используя один source.cc и импортировать только информацию о типе, например,

#include_typedef "source.cc"

Все будет проще. Компилятору легко игнорировать распределение переменных и определения функций, просто фильтруя их во время синтаксического анализа, даже до создания AST, не так ли?

Я привык к программированию в отдельных файлах исходного кода / заголовка, я, безусловно, способен выполнять разделение. Вы можете поспорить о стиле программирования, но это снизит вопрос о том, как правильно представлять логику, а о том, какой стиль программирования лучше. Я не думаю, что Java - лучший стиль программирования в контексте разделения заголовка и источника. но Java дает правильный путь.

Вы не возражаете отделить заголовки от классов? Если возможно, как вы будете смешивать их в один? Есть ли C ++ front-end, который может отделить объявление и определение в отдельные файлы из смешанных источников? Или как я могу написать такой? (Я имею в виду GCC.)

EDIT

В любом случае, я не ругаю C ++, извините, если вы получили неверную информацию из этого вопроса.

Поскольку C ++ является мультипарадигмальным языком, вы можете увидеть, как MFC устанавливает привязку сообщений с помощью магических макросов, и как библиотека boost реализует все, используя шаблоны. Когда разделение переходит в проблемную область (благодаря тому, что ONeal указывает, что домен принадлежит системе упаковки), можно попытаться выяснить, как его решить. Для меня так много стилей программирования, потому что я потратил так много времени на программирование на C ++, поэтому любое маленькое удобство накапливается в большое удобство. Реализация записи вместе с декларацией является одной из удобных. Я думаю, я могу уменьшить исходные строки по крайней мере на 10%, если мне не нужно разделять их. Вы можете спросить, если удобство так важно, почему бы просто не использовать Java? Очевидно, что C ++ отличается от Java, они не взаимозаменяемы.

Встроенная функция может решить проблему, но она вообще меняет семантику.

Ответы [ 3 ]

5 голосов
/ 18 января 2011

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

Полагаю, вы пропустили так называемые защиты заголовков - и, таким образом, получил предупреждение о переопределении.

// foo.h --------

#ifndef FOO_H
#define FOO_H

class Foo {
    void bar() { ... }
};

#endif // FOO_H

Это должно нормально работать

2 голосов
/ 18 января 2011

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

#ifndef FOO_H
#define FOO_H 1
...
#endif

Это гарантирует, что если дважды включить файл foo.h, то вторая копия увидит, что определено FOO_H, и пропустит код.параметры должны быть объявлены в .h, а не в .cc (.cpp).Причина этого заключается в том, что компилятор должен создать полный вызов функции со всеми параметрами при компиляции вызывающего кода, поэтому он должен знать значение любых параметров по умолчанию в точке вызова.Повторное их определение в определении кода является излишним и обычно рассматривается как ошибка.

2 голосов
/ 18 января 2011

Где указать значения по умолчанию для необязательных параметров?

Заголовочный файл. Аргументы по умолчанию - это просто синтаксический сахар, который вводится на сайте вызова. Чтобы дать их в точке определения не должны компилироваться.

Перемещение между встроенными и не встроенными ...?

Зависит от двух вещей: A. если производительность имеет значение, и B. если у вас есть компилятор, поддерживающий оптимизацию всей программы (это поддерживают и GCC, и MSVC ++ (не уверен в других); также называется «генерация кода во время компоновки») , Если ваш компилятор не поддерживает LTCG, вы можете получить дополнительную производительность, поместив функцию в заголовочный файл, потому что компилятор будет знать больше о коде в каждой единице перевода. Если производительность не имеет значения, постарайтесь поместить как можно больше в файл реализации. Таким образом, если вы немного измените реализацию, вам не нужно перекомпилировать весь код. С другой стороны, если ваш компилятор поддерживает LTCG, то это не имеет значения даже с точки зрения производительности, потому что компилятор оптимизирует все единицы перевода одновременно.

Вы не возражаете отделить заголовки от классов? Если возможно, как вы будете смешивать их в один?

Существуют преимущества как системы пакетов Java / C # / friends, так и преимуществ системы включения C ++. К сожалению для C ++, машины с горами памяти сделали систему Java / C #, вероятно, лучше. Проблема с такой системой пакетов заключается в том, что вам необходимо иметь возможность сохранять всю структуру программы в памяти в любой момент времени, тогда как в случае системы включения в любой момент времени в памяти должна находиться только одна единица перевода. Это может не иметь значения для среднего программиста на C ++ или Java, но при компиляции кодовой базы из многих миллионов строк кода, выполнение чего-то вроде того, что делает C ++, было бы необходимо для машин с крайне ограниченными спецификациями (например, те, которые были разработаны для запустить в 1972 году). В настоящее время хранить базу данных программы в памяти не так уж и непрактично, поэтому это ограничение больше не применяется. Но мы будем зацикливаться на подобных вещах, по крайней мере, на некоторое время, просто потому, что именно так структурирован язык. Возможно, в будущем пересмотре языка C ++ будет добавлена ​​система упаковки - по крайней мере одно предложение сделать это после C ++ 0x.

Что касается «разума» с точки зрения программиста, я не возражаю против использования любой системы, хотя разделение C ++ объявления класса и определения функции иногда приятно, поскольку сохраняет уровень отступов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...