Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Для новичков > Описание и реализация класса в разных файлах


Автор: Gryphon 2.5.2008, 09:41
Вопрос: как правильно писать программу с описанием и реализацией класса в отдельных файлах?
С такой проблемой столкнулся:

Matrix.h
Код

#include <iostream>
using namespace std;
#include <vector>
#include <string>

class Matrix
{
public:
    void show ( void );
    Matrix ( string );
    ~Matrix ( void ) { }
};


Matrix.cpp
Код

#include "Matrix.h"

void Matrix::show ( void )
{...}

Matrix::Matrix ( string str )
{...}


main.cpp
Код

#include "Matrix.h"

int main ( int argc, char *argv[] )
{
    Matrix a ("in");
    a.show ();
    return 0;
}


При компиляции на вызовах конструктора и функции из main вылезают ошибки линковки. Не видит реализации в Matrix.cpp, короче. Доктор, в чём ошибка, кроме генов?)

Автор: Fazil6 2.5.2008, 10:13
Matrix.h

Код

#ifndef MATRIX_H_H
#define MATRIX_H_H

//#include <iostream> не вижу необходимости в этом хедере
// using namespace std;  никогда не используй такую конструкцию в хедере
//#include <vector> не вижу необходимости в этом хедере
#include <string>
class Matrix
{
public:
    void show ( void );
    Matrix ( std::string );
    ~Matrix ( void ) { }
};

#endif

файл Matrix.cpp должен быть включен в проект 

Автор: Gryphon 2.5.2008, 10:22
Цитата(Fazil6 @ 2.5.2008,  10:13)
Matrix.h

Код

...
//#include <iostream> не вижу необходимости в этом хедере
// using namespace std;  никогда не используй такую конструкцию в хедере
//#include <vector> не вижу необходимости в этом хедере
...

...
файл Matrix.cpp должен быть включен в проект

0) Вектор я забыл убрать, он там по ходу в реализации понадобится)

1)  Всегда использую шапку
Код

#include <iostream>
using namespace std;

Почему это не правильно?

2) Разумеется, Matrix.cpp в проекте.

3) Ничего не изменилось(
Код

#ifndef MATRIX_H_H
#define MATRIX_H_H
...
#endif

Нельзя ли поподробнее объяснить, для чего это надо, пожалуйста?

4) Интересно... Убрал из проекта всё, кроме написанго в посте, заработало. Сейчас буду смотреть.

Автор: Gryphon 2.5.2008, 10:57
Так, всё любопытственнее и любопытственнее... Итак, проект, в котором нет ничего, кроме написанного в посте, работает. Мой изначальный проект, в котором была проблема, посложнее. Я просто не стал писать сюда весь код. А теперь приближение к нему, в котором появляестя описанная проблема:

Matrix_NxN.h
Код

#include <iostream>
using namespace std;
#include <vector>
#include <string>

template <class T> class Matrix_NxN :
    public vector<vector<T>>
{
    string s;
public:
    void show ( void );
    Matrix_NxN ( string );
    ~Matrix_NxN ( void ) { }
};


Matrix_NxN.cpp
Код

#include "Matrix_NxN.h"

template <class T>
void Matrix_NxN<T>::show ( void )
{
    cout << s << endl;
}

template <class T>
Matrix_NxN<T>::Matrix_NxN ( string str )
{
    s = str;
}


main.cpp
Код

#include "Matrix_NxN.h"

typedef Matrix_NxN <int> Matrix;

int main ( int argc, char *argv[] )
{
    Matrix a ("in");
    a.show ();
    return 0;
}


Не удивляйтесь vector'у и шаблону — это всё нужно для нормальной реализации, код которой здесь приводить ни к чему. Тестовый проект с кодом, написанном в этом посте, выдаёт пресловутую ошибку линковки.

Изменение Matrix_NxN.h на
Код

#ifndef MATRIX_NXN_H_H
#define MATRIX_NXN_H_H

#include <iostream>
using namespace std;
#include <vector>
#include <string>

template <class T> class Matrix_NxN :
    public vector<vector<T>>
{
    string s;
public:
    void show ( void );
    Matrix_NxN ( string );
    ~Matrix_NxN ( void ) { }
};

#endif

не меняет ничего.

Если реализация функций не в Matrix_NxN.cpp, а в main.cpp, всё работает. В чём может быть дело?

Автор: Carnifex 2.5.2008, 11:42
Цитата

В чём может быть дело?

В нереализованном экспорте шаблонов.
Как работает, так и пиши.

Автор: Fazil6 2.5.2008, 11:47
Цитата(Gryphon @  2.5.2008,  10:57 Найти цитируемый пост)
Если реализация функций не в Matrix_NxN.cpp, а в main.cpp, всё работает. В чём может быть дело?

в шаблонах. Нельзя разносить объявление и реализацию шаблона. Обычно для шаблона все пишут в хедере

Автор: Gryphon 2.5.2008, 12:02
Спасибо большое! 8)  smile 

Автор: vasmt 8.6.2008, 22:57
Возвращаясь к теме. Можно ли узнать, в каких еще случаях нельзя использовать описание и реализацию класса в разных файлах.
Спасибо

Автор: bsa 9.6.2008, 12:32
Цитата(vasmt @ 8.6.2008,  22:57)
Возвращаясь к теме. Можно ли узнать, в каких еще случаях нельзя использовать описание и реализацию класса в разных файлах.

В случае встраиваемых функций/методов (inline).

Цитата(Gryphon)
1)  Всегда использую шапкукод C++
Код
#include <iostream>
using namespace std;
Это ты зря. Особенно опасно using namespace std делать в заголовочных файлах. И вообще, тебе что, во всех файлах именно iostream нужен? Может в некоторых можно и ostream/istream ограничиться?
Итак, в заголовочных файлах подключать нужно то и только то, что тебе нужно (ни больше, ни меньше), так как подключив заголовочный файл пользователь ожидает, что проблем с ним не будет (все должно компилироваться без лишних телодвижений), но в то же время, это не сильно влияло на время сборки (в С++ довольно сложный синтаксис для разбора, особенно, у шаблонов, поэтому большое количество шаблонных файлов компилируется очень долго). using namespace в заголовочном файле использовать вообще очень вредно (если только внутри методов, классов или пространств имен), т.е. чтобы никто, кто подключил твой заголовочный файл случаем не получил в открытом доступе методы и классы стандартного пространства имен.
Я, например, всегда использую приставки (std::, например). Исключением являются длинные названия пространств имен, но для них я локально делаю псевдонимы (например: namespace popt = boost::program_options;). Это позволяет при последующем чтении кода точно знать, что именно я использую в данном месте.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)