Original Post
I've been using boost's shared_ptr to great effect in my game engine. Suddenly I'm seeing weird behaviour from them. I know some people here use boost, so thought maybe I could get some suggestions. (EDIT, OK this post is BIG. Just read the headers of the classes; I only put in the implementation details in case anyone spotted any silly mistakes I'd made there that may affect it. The headers should describe the problem fine though.) I define some classes as below: Shader.h Shader.cpp VertexShader.h VertexShader.cpp FragmentShader.h and I use like so (test code only!) extract from game.cpp done that way, I get a runtime error 'Pure Virtual function call' on 'v->UploadSrc()' I thought maybe shared_ptrs to abstract classes didn't work (or didn't like having child classes being allocated in their constructor), so did it like so: and still the same problem. This is strange, as surely the shared_ptr would have no pure virtual functions, as it implements it's own versions of Shader's pure virtual functions. so I'm forced to do it like this which seems to work. It doesn't break my design, but is far from perfect... Now the weird thing is, I wrote a simple test to check shared_ptr behaved how I thought it should and that works fine! Any ideas why? Also any ideas of a workaround? - I'd much rather use shared_ptrs to the baseclass in most places. Thanks for reading Dan [Edited by - mrbastard on January 14, 2005 4:32:07 PM]
#ifndef SHADER_H
#define SHADER_H
#include <string>
using namespace std;
#include "glheader.h"
class Shader
{
public:
Shader(void);
virtual ~Shader(void);
void SetSrc(string s){src=s;}
bool LoadSrc(string filename);
virtual void UploadSrc()=0;
virtual bool Compile()=0;
void Delete();
GLhandleARB GetGLname(){return GLname;}
protected:
//flags whether the src has been passed to the GL
bool inGL;
//the shader's handle
GLhandleARB GLname;
//string containing the glsl sourcecode of the shader
string src;
//the compile status of the shader
GLint compile_status;
};
#endif
#include "Shader.h"
#include <fstream>
using namespace std;
Shader::Shader(void)
{
inGL = false;
GLname = 0;
}
Shader::~Shader(void)
{
//if the shader is taking up mem on the server
if (inGL)
{
//delete it
Delete();
}
}
bool Shader::LoadSrc(string filename)
{
ifstream instream;
instream.open(filename.c_str(),ios::in);
if (instream.is_open())
{
//using the null character as a delimeter should get the whole file
getline(instream,src,'\0');
//close the file
instream.close();
return true;
}
return false;
}
void Shader::Delete()
{
glDeleteObjectARB(GLname);
}
#ifndef VERTEX_SHADER_H
#define VERTEX_SHADER_H
#include "Shader.h"
class VertexShader : public Shader
{
public:
VertexShader(void);
~VertexShader(void);
void UploadSrc();
bool Compile();
};
#endif
#include "VertexShader.h"
VertexShader::VertexShader(void)
{
this->Shader::Shader();
}
VertexShader::~VertexShader(void)
{
}
void VertexShader::UploadSrc()
{
//if there's an object in use
if(inGL)
{
//delete it
Delete();
}
const char* s = src.c_str();
GLname = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);
glShaderSourceARB(GLname,1,&s,NULL);
}
bool VertexShader::Compile()
{
glCompileShaderARB(GLname);
glGetObjectParameterivARB(GLname, GL_OBJECT_COMPILE_STATUS_ARB, &compile_status);
return compile_status;
}
#ifndef FRAGMENT_SHADER_H
#define FRAGMENT_SHADER_H
#include "Shader.h"
class FragmentShader : public Shader
{
public:
FragmentShader(void);
~FragmentShader(void);
virtual void UploadSrc();
virtual bool Compile();
};
#endif
///shadertest
boost::shared_ptr<Shader> v(new VertexShader);
boost::shared_ptr<Shader> f(new FragmentShader);
boost::shared_ptr<GPUProgram>prog(new GPUProgram);
//load shaders
v->LoadSrc("./data/perpixel.vert");
v->UploadSrc();
f->LoadSrc("./data/perpixel.frag");
f->UploadSrc();
//attach them to the program
prog->AttachShader(v);
prog->AttachShader(f);
//compile them
v->Compile();
f->Compile();
//link the program
prog->Link();
///shadertest
boost::shared_ptr<VertexShader> v(new VertexShader);
boost::shared_ptr<FragmentShader> f(new FragmentShader);
boost::shared_ptr<GPUProgram>prog(new GPUProgram);
//load shaders
v->LoadSrc("./data/perpixel.vert");
v->UploadSrc();
f->LoadSrc("./data/perpixel.frag");
f->UploadSrc();
//attach them to the program
boost::shared_ptr<Shader> shader;
shader = v;
prog->AttachShader(shader);
shader = f;
prog->AttachShader(shader);
//compile them
v->Compile();
f->Compile();
//link the program
prog->Link();
///shadertest
boost::shared_ptr<VertexShader> v(new VertexShader);
boost::shared_ptr<FragmentShader> f(new FragmentShader);
boost::shared_ptr<GPUProgram>prog(new GPUProgram);
//load shaders
v->LoadSrc("./data/perpixel.vert");
v->VertexShader::UploadSrc();
f->LoadSrc("./data/perpixel.frag");
f->FragmentShader::UploadSrc();
//attach them to the program
boost::shared_ptr<Shader> shader;
shader = v;
prog->AttachShader(shader);
shader = f;
prog->AttachShader(shader);
//compile them
v->VertexShader::Compile();
f->FragmentShader::Compile();
//link the program
prog->Link();
#include <iostream>
using namespace std;
#include <boost/shared_ptr.hpp>
using namespace boost;
struct a
{
int n;
a(){n=1;}
virtual void print() = 0;
};
struct b : public a
{
b(){n=2;}
virtual void print(){cout << n;}
};
struct c : public a
{
c(){n=3;}
virtual void print(){cout << n;}
};
int main()
{
shared_ptrsp(new b);
shared_ptrspp(new c);
sp->print();
spp->print();
return 0;
}