[완료]c++에서 <<연산자 overriding시 컴파일 에러 문제

sawa500의 이미지

C++로 행렬 class를 만들고 있는데 namespace 부분을 주석처리하면 이상없이 컴파일이 되다가도 주석을 해제하고 컴파일시키면 아래 메시지와 같은 에러를 내뱉고 있습니다. 무슨 이유로 이러는지 아래 코드를 보시고 해결방법을 아시는 분이 계시면 가르쳐주시면 감사하겠습니다. 덤으로 mat_test파일에서 C=A+B; cout << C << endl;로 하지 않고 cout << A+B << endl을 직접쓰면 에러가 나는 이유도 가르쳐 주시면 고맙겠습니다.

요약하자면
1. namespace를 적용하기전엔 compile이 되던 코드가 namespace를 적용시키면 compile에러를 내는 이유와 해결방법
2. 연산자 오버로딩을 이용하여 행렬 연산을 C=A+B; cout << C << endl;말고 직접 cout << A+B << endl;을 사용하면 에러가 나는 이유와 해결방법 => 해결되었음.

입니다.

mat_test.o(.text+0x28e): In function `main':
d:/MyProjects/C++/ebm/mat_test.cpp:13: undefined reference to `EBM::operator<<(std::ostream&, EBM::Matrix&)'
mat_test.o(.text+0x2bc):d:/MyProjects/C++/ebm/mat_test.cpp:15: undefined reference to `EBM::operator<<(std::ostream&, EBM::Matrix&)'
mat_test.o(.text+0x403):d:/MyProjects/C++/ebm/mat_test.cpp:20: undefined reference to `EBM::operator<<(std::ostream&, EBM::Matrix&)'
mat_test.o(.text+0x537):d:/MyProjects/C++/ebm/mat_test.cpp:22: undefined reference to `EBM::operator<<(std::ostream&, EBM::Matrix&)'
mat_test.o(.text+0x70b):d:/MyProjects/C++/ebm/mat_test.cpp:24: undefined reference to `EBM::operator<<(std::ostream&, EBM::Matrix&)'

mat.h 파일 내용

#ifndef __MAT_H
#define __MAT_H
 
#include <vector>
#include <string>
#include <iostream>
 
using namespace std;
 
//namespace EBM
//{
  class Matrix
  {
  public:
    Matrix();
    Matrix(size_t rows, size_t cols, double value=0.0);
    ~Matrix();
    //copy constructor
    Matrix(const Matrix& s);
 
  public:
    void resize(size_t rows, size_t cols);
    void identity(size_t mn);
    void identity(); // if rows is not equal cols, then matrix is reduced to square matrix sized by min(rows,cols)
    void print();
    void assign(size_t row, size_t col, double value);
    void trans(); // exchange row and col
 
  public:
    inline size_t rows() { return this->m; };
    inline size_t cols() { return this->n; };
 
  public:
    //operation
    Matrix operator+(Matrix B);
    Matrix operator-(Matrix B);
    Matrix operator*(Matrix B);
 
    //
    vector<double>& operator[](size_t m);
    friend ostream& operator<<(ostream& os, Matrix& mat);
 
    //assign operator
    const Matrix& operator=(const Matrix& rhs);
 
 
 
  private:
    vector<double>* v; // row vector
    size_t m;
    size_t n;
  };
  //}
 
 
 
#endif /* __MAT_H */

mat.cpp파일 내용

#include "mat.h"
 
//using namespace EBM;
 
Matrix::Matrix()
{
  this->m = 0;
  this->n = 0;
  this->v = NULL;
}
 
Matrix::Matrix(size_t rows, size_t cols, double value)
{
  this->m = rows;
  this->n = cols;
  this->v = new vector<double>[rows];
  for(size_t i=0; i<this->m; i++)
    {
      this->v[i].resize(n,value);
    }
}
Matrix::~Matrix()
{
  this->m = 0;
  this->n = 0;
  delete[] this->v;
}
 
//copy constructor
Matrix::Matrix(const Matrix& s)
{
  this->m = s.m;
  this->n = s.n;
 
  this->v = new vector<double>[s.m];
  for(size_t i=0; i<this->m; i++)
    {
      this->v[i].resize(n);
      for(size_t j=0; j<this->n; j++)
	{
	  this->v[i][j] = s.v[i][j];
	}
    }
}
 
//assign operator
const Matrix& Matrix::operator=(const Matrix& rhs)
{
  if (this != &rhs) {                                // 오른쪽의 인자가 자기자신이 아닐 경우만 진행한다.
    delete[] this->v;                             // 필요없는 메모리를 반납한다.
    this->v = new vector<double>[rhs.m];      // 새로운 메모리를 할당한다.
    this->m = rhs.m;
    this->n = rhs.n;
    for(size_t i=0; i<this->m; i++)
      {
	this->v[i].resize(n,0.0);
	for(size_t j=0; j<this->n; j++)
	  {
	    this->v[i][j] = rhs.v[i][j];
	  }
      }
  }
  return *this;                                      // 자기자신의 레퍼런스를 반환한다. 이제 따로 떨어진 대입결과가 동작할 것이다.
}
 
 
void Matrix::resize(size_t rows, size_t cols)
{
  delete[] this->v;
  this->m = rows;
  this->n = cols;
  this->v = new vector<double>[rows];
  for(size_t i=0; i<this->m; i++)
    {
      this->v[i].resize(n,0.0);
    }
}
 
void Matrix::identity(size_t mn)
{
  delete[] this->v;
  this->m = mn;
  this->n = mn;
  this->v = new vector<double>[mn];
  for(size_t i=0; i<this->m; i++)
    {
      this->v[i].resize(mn,0.0);
      for(size_t j=0; j<this->n; j++)
	{
	  if(i==j)
	    {
	      this->v[i][j] = 1.0;
	    }
	}
    }
}
 
void Matrix::identity()
{
  delete[] this->v;
  size_t m;
  m = this->m<=this->n?this->m:this->n;
  this->m = m;
  this->n = m;
  this->v = new vector<double>[m];
  for(size_t i=0; i<this->m; i++)
    {
      this->v[i].resize(m,0.0);
      for(size_t j=0; j<this->n; j++)
	{
	  if(i==j)
	    {
	      this->v[i][j] = 1.0;
	    }
	}
    }
}
 
 
vector<double>& Matrix::operator[](size_t m)
{
  return this->v[m];
}
 
ostream& operator<<(ostream& os, Matrix& obj)
{
  size_t m = obj.rows();
  size_t n = obj.cols();
  os << m << " x " << n << endl;
  for(size_t i=0; i<m; i++)
    {
      os << "[ ";
      for(size_t j=0; j<n; j++)
	{
	  os << obj[i][j];
	  if(j<n-1)
	    {
	      os << "  ";
	    }
	}
      os << " ] " << endl;
    }
 
  return os;
}
 
void Matrix::print()
{
  cout << this->m << " x " << this->n << endl;
  for(size_t i=0; i<this->m; i++)
    {
      cout << "[ ";
      for(size_t j=0; j<this->n; j++)
	{
	  cout << this->v[i][j];
	  if(j<this->n-1)
	    {
	      cout << "  ";
	    }
	}
      cout << " ] " << endl;
    }
}
 
 
Matrix Matrix::operator+(Matrix B)
{
  Matrix C(this->m,this->n, 0.0);
 
  for(size_t i=0; i<this->m; i++)
    {
      for(size_t j=0; j<this->n; j++)
	{
	  C.v[i][j] = this->v[i][j] + B.v[i][j];
	}
    }
  return C;
}
 
Matrix Matrix::operator-(Matrix B)
{
  Matrix C(this->m, this->n, 0.0);
  for(size_t i=0; i<this->m; i++)
    {
      for(size_t j=0; j<this->n; j++)
	{
	  C.v[i][j] = this->v[i][j] - B.v[i][j];
	}
    }
  return C;
}
 
Matrix Matrix::operator*(Matrix B)
{
  Matrix C(this->m, B.n, 0.0);
 
  for(size_t i=0; i<this->m; i++)
    {
      for(size_t j=0; j<B.n; j++)
	{
	  for(size_t k=0; k<this->n; k++)
	    {
	      C.v[i][j] = C.v[i][j] + this->v[i][k]*B.v[k][j];
	    }
	}
    }
  return C;
}
 
 
void Matrix::assign(size_t row, size_t col, double value)
{
  this->v[row][col] = value;
}
 
void Matrix::trans()
{
  Matrix T(this->n, this->m, 0.0);
 
  for(size_t i=0; i<this->m; i++)
    {
      for(size_t j=0; j<this->n; j++)
	{
	  T[j][i] = this->v[i][j];
	}
    }
  this->m = T.m;
  this->n = T.n;
  *this = T;
}

mat_test.cpp 파일 내용

#include "mat.h"
 
//using namespace EBM;
 
int main()
{
  Matrix A(2,2);
  Matrix B(2,2,3.0);
  Matrix C;
  vector<double> v;
  A[0][1] = 100;
  A[1][0] = 200;
 
 
  C = A+B;
  cout << "A+B = "<< endl << A+B << endl;
  C = A-B;
  cout << "A-B = "<< endl << C << endl;
  C = A*B;
  cout << "A*B = "<< endl << C << endl;
  return 0;
}

윤용근의 이미지

ostream& 나 istream&의 연산자 오버로딩은

헤더파일안에서 해야되는게 아닌가 싶은데요..

아닌가요? ;; 기억이 가물가물

cdecl의 이미지

1.
friend ostream& operator<<(ostream& os, Matrix &obj);
=> friend ostream& operator<<(ostream& os, Matrix obj); (1)
=> friend ostream& operator<<(ostream& os, const Matrix &obj); (2)

(1)의 내용대로 하면 바로 컴파일 될것이라 판단됩니다.
(2)의 내용처럼 한다면 몇개의 멤버함수를 const 처리 해야 합니다.

2.
const Matrix& operator=(const Matrix& rhs);
=> Matrix& operator=(const Matrix& rhs);

대입연산자의 원형은 아래것이 맞습니다.
위에처럼 한다면 다음과 같은 식이 위배됩니다.

a = b = c;

--
cdecl

--
cdecl

sawa500의 이미지

cdecl님께서 알려주신 대로 바꾸니 cout << A+B << endl; 문제가 바로 해결되었습니다.
헌데 namespace EBM에 쳐진 주석을 해제하고 컴파일 해보면

undefined reference to `EBM::operator<<(std::ostream&, EBM::Matrix)

이라는 에러메시지를 보내는데 왜 못찾겠다는 건지 모르겠습니다.

sawa500의 이미지

자문자답이 되어버렸네요.

namespace를 쓸때 헤더파일과 소스파일에 둘다 namespace 블록으로 묶어주어야하는 걸 모르고 소스파일에다가는 using namespace를 사용해서 생긴 에러였습니다.

도움주신 분들 모두 감사합니다.

philnet의 이미지

mat.cpp에 있는 Matrix의 definition이, declaration과 동일한 namespace에 존재하지 않아서 그런 것 같습니다.

mat.cpp에서,

using namespace EBM;

를 사용하는 대신,

mat.cpp의 Matrix의 definition들을 namespace EBM { }에 넣어주시면 잘 될 겁니다.

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.