Jump to content
  • Advertisement

Archived

This topic is now archived and is closed to further replies.

johnnyBravo

Is it possible to make a class accept value null?

This topic is 5384 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Ive got an Image class for directx that loads textures. and ive got a drawVertex function that requires you enter an image from the image class. But sometimes if you don''t want an image i want it so you can make it equal null. how would i do this? eg
//image class

class Image {
public:
	LPDIRECT3DTEXTURE9 lp_Texture;
	int width;
	int height;
	void init(char filename[], DWORD colourKey);

	~Image()
	{
		if(lp_Texture != NULL )
			lp_Texture->Release();
		
void Image::init(char filename[], DWORD colourKey=0)
{
	lp_Texture=NULL;
	D3DXIMAGE_INFO fileInfo={NULL};
	D3DXGetImageInfoFromFile(filename,&fileInfo);
	width =fileInfo.Width;
	height=fileInfo.Height;
	D3DXIMAGE_INFO d3dxImageInfo;
	D3DXCreateTextureFromFileEx( D3D::lp_Device, filename, fileInfo.Width, fileInfo.Height, 1, D3DPOOL_DEFAULT, D3DFMT_UNKNOWN, D3DPOOL_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, colourKey, &d3dxImageInfo, NULL, &lp_Texture );
	}

//draw vertex function

static void drawVertice(enum _D3DPRIMITIVETYPE type, int index, int triangles,	Image &image )
	{
		lp_Device->SetTexture( 0, image.lp_Texture );
		lp_Device->DrawPrimitive( type, index, triangles );
	}

//running drawvertex, i want to enter NULL for the class instead of an image class, so it knows there is no image to use

D3D::drawVertice(D3DPT_TRIANGLESTRIP,0,1,NULL);
thanks,

Share this post


Link to post
Share on other sites
Advertisement
Just check if the image pointer is valid. ie: check if it''s not 0, becuase NULL is actually just a define for 0 in C++.


static void drawVertice(enum _D3DPRIMITIVETYPE type, int index, int triangles, Image *image )
{
if( image )
lp_Device->SetTexture( 0, image.lp_Texture );
lp_Device->DrawPrimitive( type, index, triangles );
}



:::: [ Triple Buffer ] ::::

Share this post


Link to post
Share on other sites
when i have "Image *image" instead of "Image &image i get the error
quote:

error C2228: left of ''.lp_Texture'' must have class/struct/union type



and if i try put null in while ive got "Image &image"
i get the error
quote:

error C2664: ''drawVertice'' : cannot convert parameter 4 from ''const int'' to ''class graphic::Image &''
A reference that is not to ''const'' cannot be bound to a non-lvalue



so what to do?

Share this post


Link to post
Share on other sites
quote:
Original post by johnnyBravo
when i have "Image *image" instead of "Image &image i get the error
quote:

error C2228: left of ''.lp_Texture'' must have class/struct/union type





use image->lp_Texture

Share this post


Link to post
Share on other sites
ah thanks,

just a quick question, is there any advantage or disadvantage of using pointers instead of references in functions apart from being able directly edit or whatever the referenced thing? The only reasion i orginally used references was so i didnt have to type "&" infront of every thing.

Share this post


Link to post
Share on other sites
quote:
Original post by johnnyBravo
Ive got an Image class for directx that loads textures.

and ive got a drawVertex function that requires you enter an image from the image class.

But sometimes if you don''t want an image i want it so you can make it equal null.

how would i do this?

You could possibly use the Null Object Idiom in conjunction with function overloading. For example:


#include <iostream>

class Image
{
};

class Null
{
} nil;

void foo(int, int, int, const Image&)
{
std::cout << "foo with Image\n";
}

void foo(int, int, int, const Null&)
{
std::cout << "foo with Null\n";
}

int main()
{
foo(1,2,3, Image());
foo(1,2,3, nil);
}


Here, you create a globally-scoped entity called "nil" of a type distinct from all others (in this case Null) and you use it for overloading the function. This simulates how languages such as Python and Lisp work, and is arguably more sane than the built-in way in which C++ deals with null (where it has no distinct type of its own).

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
quote:
Original post by SabreMan
You could possibly use the Null Object Idiom in conjunction with function overloading. For example:
&lt;source code&gt;
Here, you create a globally-scoped entity called "nil" of a type distinct from all others (in this case Null) and you use it for overloading the function. This simulates how languages such as Python and Lisp work, and is arguably more sane than the built-in way in which C++ deals with null (where it has no distinct type of its own).

Is there an advantage to this as opposed to overloading the function with one less argument, eg:

class Image
{
};
void foo(int, int, int, const Image&)
{
// draw with image

}

void foo(int, int, int)
{
// draw without image

}

int main()
{
foo(1,2,3, Image());
foo(1,2,3);
}

To the OP:
In fact, in this particular case, I would expect the use of a pointer, with NULL checks within the function would be better, since it would a) let you pass in a null pointer without the caller knowing that it''s null, and b) mean you don''t have to duplicate code between two versions of the function (nb: of course, duplication could be reduced or eliminated even if you choose to overload the function, by breaking it down into separate sub-functions, but depending on what exactly you need to do in the overloaded function, this may result in less readable code).

John B
[gdnick: JohnBSmall, but I''m at school and don''t wish to log in]

Share this post


Link to post
Share on other sites
quote:
Original post by Anonymous Poster
Is there an advantage to this as opposed to overloading the function with one less argument

Maybe, maybe not. It really depends on how the OP wants to call the function, which is not something for me to decide.
quote:

In fact, in this particular case, I would expect the use of a pointer, with NULL checks within the function would be better

A way of extending the Null Object idea might be to derive an hierarchy for Images, where the necessary logic is polymorphic across different types of Image. The hierarchy could then include a NullImage type and the call-site could remain ignorant of the concrete type passed through. There''s actually other problems in the OP''s code that I didn''t comment on, such as lack of encapsulation and cohesiveness. Resolution of these problems would probably result in the use of polymorphic despatch dropping out as the natural solution.
quote:

it would a) let you pass in a null pointer without the caller knowing that it''s null

This really depends on the creation policy for Image types.
quote:

b) mean you don''t have to duplicate code between two versions of the function

This is a two-way argument. If the code is switching on the (conceptual) type of something, then it really contains two different implementations of something. Whether you perceive that as a problem depends on your coding ethics, I suppose. I''ve grown very suspicious of explicit type-switches. The only reason this is not perceived as a type-switch in C++ is because C++ handles nulls in an incredibly stupid way. Its still conceptually a type-switch.

Share this post


Link to post
Share on other sites
quote:
Original post by SabreMan
quote:
Original post by me
Is there an advantage to this as opposed to overloading the function with one less argument

Maybe, maybe not. It really depends on how the OP wants to call the function, which is not something for me to decide.

That''s true of course, but ignoring the OP''s specific problem for a moment, is there a situation where using a null parameter instead of no parameter at all would give an advantage (other than simple stylistic preference)?
quote:
A way of extending the Null Object idea might be to derive an hierarchy for Images, where the necessary logic is polymorphic across different types of Image. The hierarchy could then include a NullImage type and the call-site could remain ignorant of the concrete type passed through. There''s actually other problems in the OP''s code that I didn''t comment on, such as lack of encapsulation and cohesiveness. Resolution of these problems would probably result in the use of polymorphic despatch dropping out as the natural solution.

Perfectly true. Do you believe that such class hierarchies should be used even if they result in a very simple (but, I suspect, not uncommon) trio of classes?
ie, abstract base class defining interface, single real concrete class implementing interface, and a concrete null class implementing everything (or nearly everything) with empty functions.
quote:
quote:
it would a) let you pass in a null pointer without the caller knowing that it''s null

This really depends on the creation policy for Image types.

True of course.
quote:
If the code is switching on the (conceptual) type of something, then it really contains two different implementations of something. Whether you perceive that as a problem depends on your coding ethics, I suppose. I''ve grown very suspicious of explicit type-switches. The only reason this is not perceived as a type-switch in C++ is because C++ handles nulls in an incredibly stupid way. Its still conceptually a type-switch.

True. However, it is (again, I suspect - I can''t provide statistics) common to have a situation in which a type-switch is a matter of running through the full code path for one type, but excluding part of that code path for another type (generally, the null type). Do you believe that it is still bad practice if the type-switches consist of having blocks of the function code wrapped up in if statements? And if so, what do you think is the best way of organising the code in this case?
// by breaking the function down?  something like:

void foo(int a, int b, const Object* c)
{
// code block 1

if (c != 0)
{
// code block 2

}
// block 3

if (c != 0)
// block 4 (single statement block)

// block 5

}

// Should foo be broken up? Becoming:

void foo(int a, int b, const Object& c)
{
block_1_code();
block_2_code(a, c);
block_3_code(b);
block_4_code(c);
block_5_code();
}

void foo(int a, int b, const Null& c)
{
block_1_code();
block_3_code(b);
block_5_code();
}

// or perhaps an attempt should be made to remove all type

// specific code from functions that aren''t members of the

// type they''re operating with, so that abstract interfaces

// can be used to remove all explicit type checks

// eg,

void foo(int a, int b, const Object* c)
{
// code block 1

if (c != 0)
{
c->bar(a);
}
// block 3

if (c != 0)
c->do_some_stuff();
// block 5

}
// where Object has become an abstract class, and foo() is

// given a pointer to an instance of a concrete implementation

// of the Object interface


John B

Share this post


Link to post
Share on other sites

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!