1

I have a class defined in a header and properly implemented(I think), and that is properly included(I think) wherever I try to use it.

I think I am missing something in regards to some basic syntax surrounding class definition.

I have read pretty much every C++ "undefined reference to class constructor" question on stackoverflow, but none of them seem to apply to my situation.

main.cpp

#include "headers/init.h"

int main()
{

  GameInstance *game = new GameInstance(60,480,480,"window");

}

init.cpp

#include "../headers/init.h"
...
Shader vertex("../shaders/vertex.glsl", GL_VERTEX_SHADER);
...

shader.h

#ifndef SHADER_H
#define SHADER_H

#include <string>
#include <iostream>
#include <GL/glew.h>
#include <GL/gl.h>

#include <fstream>
class Shader
{
  std::string sh_contents;

  std::ifstream sh_source;

  GLenum sh_type;
  GLuint sh_id;

public:
  Shader(const char path[], GLenum p_type );
  void compile(GLsizei p_count);

  char* geterror();

};
#endif // SHADER_H

shader.cpp

#include "../headers/shader.h"

Shader::Shader(const char path[], GLenum p_type)
{
  sh_type = p_type;

  sh_source.open(path);
  if(sh_source.is_open())
  {
    sh_source >> sh_contents;
  }
  else
  {
    std::cout << "Shader error: couldn't read from file specified!";
  }


}

void Shader::compile(GLsizei p_count)
{
  sh_id = glCreateShader(sh_type);
  const char * buffer = sh_contents.c_str();
  int length = sh_contents.length();
  glShaderSource(sh_id, p_count, &buffer, &length);
  glCompileShader(sh_id);

}
char* Shader::geterror()
{
  if(glIsShader(sh_id))
  {
    GLint sh_status;
    glGetShaderiv(sh_id,GL_COMPILE_STATUS, &sh_status);
    if(sh_status == GL_FALSE)
    {
      GLint er_length;
      glGetShaderiv(sh_id, GL_INFO_LOG_LENGTH,&er_length);
      char* er_return;
      glGetShaderInfoLog(sh_id, er_length, &er_length, er_return);
      glDeleteShader(sh_id);
      return er_return;

    }
    else
    {
      char* er_return = '\0';
      return er_return;
    }
  }
}

Edit #1:

The error:

/home/dok/SDL2/ngin/engine/source/init.cpp|71|undefined reference to `Shader::Shader(char*, unsigned int)'|

Edit #2:

I was able to compile the source with gpp via a BASH terminal, and it compiled effortlessly(note: I have updated the code as per many answerers' suggestion), so it seems this is a Code::Blocks issue.

This is the command I used to compile my program with gpp: g++ main.cpp source/init.cpp source/shader.cpp -lSDL2 -lGLEW -lGL

This is my CodeBlocksProject file:

ngin.cpb

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<CodeBlocks_project_file>
    <FileVersion major="1" minor="6" />
    <Project>
        <Option title="engine" />
        <Option pch_mode="2" />
        <Option compiler="gcc" />
        <Build>
            <Target title="Debug">
                <Option output="bin/Debug/engine" prefix_auto="1" extension_auto="1" />
                <Option object_output="obj/Debug/" />
                <Option type="1" />
                <Option compiler="gcc" />
                <Compiler>
                    <Add option="-g" />
                </Compiler>
                <Linker>
                    <Add library="SDL2" />
                    <Add library="GLEW" />
                    <Add library="GL" />
                </Linker>
            </Target>
            <Target title="Release">
                <Option output="bin/Release/engine" prefix_auto="1" extension_auto="1" />
                <Option object_output="obj/Release/" />
                <Option type="1" />
                <Option compiler="gcc" />
                <Compiler>
                    <Add option="-O2" />
                </Compiler>
                <Linker>
                    <Add option="-s" />
                </Linker>
            </Target>
        </Build>
        <Compiler>
            <Add option="-Wall" />
            <Add option="-fexceptions" />
        </Compiler>
        <Unit filename="headers/init.h" />
        <Unit filename="headers/shader.h" />
        <Unit filename="main.cpp" />
        <Unit filename="shaders/fragment.glsl" />
        <Unit filename="shaders/vertex.glsl" />
        <Unit filename="source/init.cpp" />
        <Unit filename="source/shader.cpp">
            <Option target="&lt;{~None~}&gt;" />
        </Unit>
        <Extensions>
            <code_completion />
            <envvars />
            <debugger />
        </Extensions>
    </Project>
</CodeBlocks_project_file>
balrog
  • 56
  • 8
  • what specifically is the error saying? could you edit the post with the exact error output? – Syntactic Fructose Jul 14 '14 at 17:26
  • Can you add the exact error message that you're seeing, please? – jwismar Jul 14 '14 at 17:28
  • Ahh yes, here it is, sorry. – balrog Jul 14 '14 at 17:31
  • 2
    Note: Please get used to 'const char*' –  Jul 14 '14 at 17:32
  • 1
    How exactly are you linking the program? Is `shader.cpp` being linked in? – Mike Seymour Jul 14 '14 at 17:39
  • @MikeSeymour I was just about asking the same now ... @_OP Also check [all the answers here](http://stackoverflow.com/questions/12573816/what-is-an-undefined-reference-unresolved-external-symbol-error-and-how-do-i-fix) first – πάντα ῥεῖ Jul 14 '14 at 17:40
  • I am using the code::blocks IDE, and I am certain that it links the source in the project automatically, although I guess that could very well be the issue. How would I manually link it? – balrog Jul 14 '14 at 17:42
  • Is your Shader.cpp file being compiled in your project? The error tells you are using a well-defined constructor but the linker cannot find the actual implementation of it. – ebasconp Jul 14 '14 at 17:43
  • At least, you have a circular dependency between shader.h and init.h (but that should make trouble at compile time) –  Jul 14 '14 at 17:45

1 Answers1

1

You declared the constructor as

Shader(char* path, GLenum p_type);

though as the error message says you are using constructor declared as

Shader(char*, unsigned int);

that is the second parameters do not coincide and there is no implicit conversion from type unsigned int to type GLenum.

I do not know how the type GLenum is defined but you could for example try to call the constructor the following way

Shader vertex("../shaders/vertex.glsl", static_cast<GLenum>( GL_VERTEX_SHADER) );

using explicit conversion from type unsigned int to type GLenum

Also take into account that you are using a string literal as the first argument. It has type const char []. So it may not be used as an argument. You shoud declare the first parameter as const char *

Also you have recursive inclusiion of headers. Header shader.h contains init.h and init.h contains shader.h.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335