18

Вопрос по c++, class, syntax – Можно ли избежать повторения имени класса в файле реализации?

Есть ли способ избежатьGraph:: повторение в файле реализации, но все же разделить класс на заголовок + реализация? Например, в:

Заголовочный файл:

#ifndef Graph_H
#define Graph_H

class Graph {
public:
    Graph(int n);
    void printGraph();
    void addEdge();
    void removeEdge();
};

#endif

Файл реализации:

Graph::Graph(int n){}
void Graph::printGraph(){}
void Graph::addEdge(){}
void Graph::removeEdge(){}

Это далеко не очень обременительная задача, и я никогда не чувствовал необходимости избегать этого. Моей первой реакцией было «вау, на что жаловаться». Но после того, как я подумал об этом, было бы целесообразно, гипер-удобно и семантически / организационно полезно, если бы было ключевое слово / комбинация, такая какclass namespace Thingy { это означало, что все в его фигурных скобках были неявно квалифицированы сThingy::, Не упоминается в OP, но это, очевидно, охватывает определенияstatic переменные тоже. Кажется очень логичным продолжениемnamespace, Люди, помните, вы услышали это здесь первым!

от underscore_d

Я знаю, что это правильно, но я спрашиваю, есть ли другой способ без необходимости повторять Graph :: ..

от Ofek Ron

Это выглядит правильно, если вы не забыли#include заголовок в реализации.

от dasblinkenlight

Вы спрашиваете, если вы можете избежать вводаGraph:: в реализации?

от GManNickG

Я мог бы также попробовать!groups.google.com/a/isocpp.org/forum/?fromgroups#!topic/…

от underscore_d
7 ответов
2

Если вы спрашиваете, можете ли вы определить функцию-член, такую как

Graph::printGraph без указания имени класса квалификации, тогда ответ - нет, не так, как вы хотите. Это невозможно в C ++:

implementation file:

void printEdge(){};

Вышеуказанное будет скомпилировано просто отлично, но оно не будет выполнять то, что вы хотите. Он не будет определять функцию-член с тем же именем вGraph учебный класс. Скорее, он объявит и определит новую свободную функцию с именемprintEdge.

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

// Header File
class A
{
  void foo();
};

class B
{
  void foo();
};

void foo();

// Implementation File
void foo()
{
}

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

1

Code:

        //yes it is possible using preprocessor like this:

        #define $ ClassName //in .cpp 

    void $::Method1() 
    { 
    } 

    //or like this: in the header .h:

        #undef $
        #define $ ClassName' 

// but you have to include the class header in last #include in your .cpp:

        #include "truc.h"
        #include "bidule.h" ...
        #include "classname.h" 

        void $::Method() { }  

        //i was using also 
        #define $$ BaseClass 
        //with single inheritance  than i can do this: 

        void $::Method() 
        { 
        $$::Method(); //call base class method 
        } 

        //but with a typedef defined into class like this it's better to do this: 
        class Derived : Base 
        { 
        typedef Base $$;  

    }
2

Нет

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

Вы, конечно, правы для текущего стандарта. Я хотел бы сделать вид, что вы говорите гипотетически, хотя ;-) Так что в соответствии с моими комментариями к ФП: вы очень легко устраните неоднозначность, используя предложенныйnamespace class определить членов:open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0223r0.html - и ничего себе, надеюсь, это будет принято ... & amp; мне очень грустно, кажется, что пропустил C ++ 17 :( Если кто-то судит об этом тривиально на СУХОЙ основе, просто подумайте о (A) интуитивных параллелях с нормальнымnamespace & Амп; особенно (B) реализацииtemplate функции вне линии, что мучительно.

от 
9

Я предполагаю

что это позволит избежать большого количества «ненужных печатаний». К сожалению, нет никакого способа избавиться от области (как сказали многие другие ответы), однако, что я делаю лично, так это получаю класс, определенный со всеми моими прототипами функций в хороших строках, затем копирую / вставляю в файл реализации, затем ctrl -c ваше ClassName :: в буфере обмена и запустить строку с Ctrl-V.

0

РЕДАКТИРОВАТЬ

я неправильно понял ваш вопрос :( это будет ответом на вопрос, можно ли разделить заголовочные файлы. Извините

Ответ прост: вы можете разбить c ++-файл, но не можете разбить заголовочные файлы.

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

например:

class Foo {
   double bar;  //8 bytes
   int goo;  //4 bytes
}

«новый Foo ()»; потребует выделения 12 байт памяти. Но если бы вам было позволено распространить определения классов на несколько файлов (то есть, на файлы с разделенными заголовками), вы легко запутались бы в этом. Ваш компилятор никогда не узнает, сказали ли вы ему все о классе или нет. Разные места в вашем коде могут иметь разные определения вашего класса, что приведет либо к ошибкам сегментации, либо к чрезвычайно криптическим ошибкам компилятора.

Например:

h1.h:

class Foo {
   double bar;  //8 bytes
   int goo;  //4 bytes
}

h2.h:     #include & quot; h1.h & quot;

class Foo {
   double goo;  //8 bytes
}// we extend foo with a double.

foo1.cpp:

#include "foo1.h"

Foo *makeFoo() {
   return new Foo();

}

foo2.cpp:

#include "foo2.h"

void cleanupFoo(Foo *foo) {
   delete foo;
}

foo1.h:

#include "h1.h"

Foo *makeFoo();

foo2.h:

#include "h1.h"
#include "h2.h"

void cleanupFoo(Foo *foo)

main.cpp:

#include foo1.h
#include foo2.h

void main() {
    Foo *foo = makeFoo();
    cleanupFoo(foo);
}

Теперь очень внимательно проверьте, что произойдет, если вы сначала скомпилируете main.cpp в main.o, затем foo1.cpp в foo1.o и foo2.cpp в foo2.o, и, наконец, свяжите их все вместе. Это должно скомпилироваться, но makeFoo () выделяет что-то еще, чем освобождается cleanupFoo ().

Итак, у вас есть это, не стесняйтесь разделять файлы .cpp, но не разделяйте классы по заголовочным файлам.

5

Нет

нет. По крайней мере, не напрямую. Вы могли бы пойти на приемы препроцессора, ноdon't do it.

#define IMPL Graph::

IMPL Graph(int n){}
void IMPL printGraph(){}
void IMPL addEdge(){}
void IMPL removeEdge(){}

Кроме того, вы не должны дажеwant to сделай это. Какой смысл. Помимо того, что это правило C ++, оно позволяет вам знать, что вы на самом деле реализуете функцию-член.

Вы также можете определить их в отдельном файле и#include их в теле класса.

от 

Э-э, действительно ли разумно сказать "не делай этого ... вот как!"

от 

@Pubby: Это так отвратительно, Я ЛЮБЛЮ ЭТО !!! foo.hclass Foo { int foo (); };, Foo.nsFoo::, Foo.cppvoid #include "Foo.ns" foo () { return 1 } (переводы строки вокруг #include)

от 

Спасибо. Я ДЕЛАЮ ЭТО прямо сейчас :-)

от 

@GManNickG Я нахожу это так, да. Мне лично нравится это знать ...

от 
12

Если вы не хотите вводить & quot

Graph :: & quot; перед printGraph, addEdge и т. д., к сожалению, ответ - «нет». «Частичный класс» функция, подобная C #, недоступна в C ++, и имя любого класса (например, «Graph») не является пространством имен, это область видимости.

+1 за два вдохновляющих способа посмотреть на ограничение.

от 

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