Можно ли избежать повторения имени класса в файле реализации?
Есть ли способ избежать повторения 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(){}
Ответы
Ответ 1
Я предполагаю, что это избежать много "ненужного ввода". К сожалению, нет способа избавиться от объема (как было сказано многими другими ответами), однако то, что я лично делаю, получает класс, определенный всеми моими прототипами функций в хороших строках, а затем копирует/вставляет в файл реализации, затем ctrl-c ваш ClassName:: на клипе и запустите линию с помощью ctrl-v.
Ответ 2
Если вы хотите не печатать "Graph::" перед printGraph, addEdge и т.д., то ответ "нет", к сожалению. Функция "частичного класса", аналогичная С#, недоступна в С++, а имя любого класса (например, "График" ) не является пространством имен, это область.
Ответ 3
Нет, нет. Не по крайней мере. Вы можете использовать препроцессорные трюки, но не делать этого.
#define IMPL Graph::
IMPL Graph(int n){}
void IMPL printGraph(){}
void IMPL addEdge(){}
void IMPL removeEdge(){}
Кроме того, вы даже не должны этого делать. Какой смысл. Помимо того, что это правило С++, оно позволяет вам знать, что вы на самом деле реализуете функцию-член.
Ответ 4
Нет, нет способа избежать этого. В противном случае, как вы узнаете, является ли заданное определение функции для функции класса или для статической функции?
Ответ 5
Если вы спрашиваете, можете ли вы определить функцию-член, такую как Graph::printGraph
, не указав квалификацию имени класса, тогда ответ будет не таким, как вы хотите. Это невозможно в С++:
файл реализации:
void printEdge(){};
Выше будет компилироваться просто отлично, но он не будет делать то, что вы хотите. Он не будет определять функцию-член с тем же именем в классе Graph
. Скорее, он объявит и определит новую свободную функцию под названием printEdge
.
Это хорошо и правильно, если с вашей точки зрения немного боль, потому что вам просто понадобятся две функции с тем же именем, но в разных областях. Рассмотрим:
// Header File
class A
{
void foo();
};
class B
{
void foo();
};
void foo();
// Implementation File
void foo()
{
}
В какой области должно применяться определение? С++ не ограничивает вас наличием разных функций с одинаковыми именами в разных областях, поэтому вы должны сообщить компилятору, какую функцию вы определяете.
Ответ 6
//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 better to do this:
class Derived : Base
{
typedef Base $$;
}
Ответ 7
EDIT: я неправильно прочитал ваш вопрос:( Это был бы ответ на вопрос, можете ли вы разделить заголовочные файлы. sorry
Простой ответ: вы можете разделить С++ файл, но вы не можете разделить заголовочные файлы.
Причина довольно проста. Всякий раз, когда ваш компилятор должен скомпилировать конструктор, он должен точно знать, сколько памяти ему нужно выделить для такого объекта.
например:
class Foo {
double bar; //8 bytes
int goo; //4 bytes
}
'new Foo()' потребует выделения 12-байтовой памяти. Но если вам разрешено расширять определения классов по нескольким файлам (т.е. Разделять файлы заголовков), вы легко можете избавиться от этого. Ваш компилятор никогда не узнает, рассказывали ли вы об этом классе, или нет. В разных местах вашего кода могут быть разные определения вашего класса, что приводит к ошибкам сегментации или чрезвычайно криптовальным ошибкам компилятора.
Например:
h1.h:
class Foo {
double bar; //8 bytes
int goo; //4 bytes
}
h2.h: #include "h1.h"
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() выделяет someting else then cleanupFoo() deallocated.
Итак, у вас есть это, не стесняйтесь разделить файлы .cpp, но не разделяйте классы по файлам заголовков.