Разделение класса C ++ на файлы теперь не будет компилироваться - PullRequest
1 голос
/ 27 апреля 2010

Я учу себя писать классы на C ++, но не могу заставить компиляцию пройти. Если вы поможете мне понять не только как, но и почему, это будет очень цениться. Заранее спасибо! Вот мои три файла:

make_pmt.C

#include <iostream>
#include "pmt.h"

using namespace std;


int main() {
    CPMT *pmt = new CPMT;
    pmt->SetVoltage(900);
    pmt->SetGain(2e6);

    double voltage = pmt->GetVoltage();
    double gain= pmt->GetGain();

    cout << "The voltage is " << voltage
         << " and the gain is " << gain << "." <<endl;

    return 0;
}

pmt.C

#include "pmt.h"

using namespace std;

class CPMT {
    double gain, voltage;
    public:
        double GetGain() {return gain;}
        double GetVoltage() {return voltage;}

        void SetGain(double g) {gain=g;}
        void SetVoltage(double v) {voltage=v;}
};

pmt.h

#ifndef PMT_H
#define PMT_H 1

using namespace std;

class CPMT {
    double gain, voltage;
    public:
        double GetGain();
        double GetVoltage();

        void SetGain(double g);
        void SetVoltage(double v);
};

#endif

И для справки я получаю ошибку компоновщика (верно?):

Undefined symbols:
  "CPMT::GetVoltage()", referenced from:
      _main in ccoYuMbH.o
  "CPMT::GetGain()", referenced from:
      _main in ccoYuMbH.o
  "CPMT::SetVoltage(double)", referenced from:
      _main in ccoYuMbH.o
  "CPMT::SetGain(double)", referenced from:
      _main in ccoYuMbH.o
ld: symbol(s) not found
collect2: ld returned 1 exit status

Ответы [ 6 ]

6 голосов
/ 27 апреля 2010

Сначала немного таксономии.
Это

class CPMT {
    public:
        double GetGain();
        // ...
};

определяет класс без определения функций-членов.Этот

class CPMT {
    public:
        double GetGain() {return gain;}
        // ...
};

определяет тот же класс, а также определяет встроенные функции-члены (неявно).Это

double CPMT::GetGain() {return gain;}
// ...

определяет функции-члены (не встроенные).

Теперь, если вы хотите отделить реализацию от интерфейса, ваш заголовок должен определить класс, а файл реализации должен определить его функции-члены.Таким образом, чистое определение класса

class CPMT {
    public:
        double GetGain();
        //...
};

входит в заголовочный файл, а реализация

double CPMT::GetGain() {return gain;}
// ...

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

Есть два способа встроить функцию-член.Один из них - определить его в пределах определения его класса

class CPMT {
    public:
        double GetGain() {return gain;}
        // ...
};

, что неявно делает его inline.Другой - явно встроить его

class CPMT {
    public:
        double GetGain();
        //...
};

inline double CPMT::GetGain() {return gain;}
// ...

В обоих случаях реализация должна находиться в заголовочном файле.

6 голосов
/ 27 апреля 2010

pmt.C будет выглядеть так:

#include "pmt.h"

using namespace std;

double CPMT::GetGain() {return gain;}
double CPMT::GetVoltage() {return voltage;}

void CPMT::SetGain(double g) {gain=g;}
void CPMT::SetVoltage(double v) {voltage=v;}

Я скомпилировал это так:

g++ make_pmt.C pmt.C

Вам также нужно добавить конструктор и инициализировать усиление и напряжение.

4 голосов
/ 27 апреля 2010

В pmt.c вы переопределяете класс. Вместо этого вы должны просто определить его функции:

double CPMT::GetGain() { return gain; }
double CPMT::GetVoltage() {return voltage;}

void CPMT::SetGain(double g) {gain=g;}
void CPMT::SetVoltage(double v) {voltage=v;}

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

4 голосов
/ 27 апреля 2010

Синтаксис вашего файла pmt.C неверен. Следует читать

double CPMT::GetGain() {return gain;}
double CPMT::GetVoltage() {return voltage;}
void CPMT::SetGain(double g) {gain=g;}
void CPMT::SetVoltage(double v) {voltage=v;}
1 голос
/ 27 апреля 2010

Похоже, вы компилируете и связываете отдельные файлы .C, которые сами по себе не являются полными. Вам нужно сначала скомпилировать их, чтобы получить файл .o, а затем связать файлы .o, чтобы получить конечный исполняемый файл. Это все можно сделать с помощью:

g++ make_pmt.C pmt.C

Также в pmt.C должно быть только определение функций, объявленных в заголовочном файле.

1 голос
/ 27 апреля 2010

Попробуйте переименовать файлы .cpp или .cxx, ваш компилятор может предположить, что .C означает, что это C, а не C ++, что, как представляется, имеет место, поскольку не искажает имена.

...