Improvements to my RGBA class

Hey guys, here is an RGBA class I made, part of a bigger class interface. Any improvements can you suggest. If it interests you, here is a question I asked about my class: http://stackoverflow.com/questions/39182661/advantages-of-calling-named-lambda-in-class-constructor-vs-calling-an-actual-pri
Here is my code below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
struct RGBA
{
	RGBA(int red, int green, int blue, int alpha = 255) :
		m_red{ validate_color(red) },
		m_green{ validate_color(green) },
		m_blue{ validate_color(blue) },
		m_alpha{ validate_color(alpha,255) }
	{}
	inline int get_red() const
	{
		return m_red;
	}
	inline int get_green() const
	{
		return m_green;
	}
	inline int get_blue() const
	{
		return m_blue;
	}
	inline int get_alpha() const
	{
		return m_alpha;
	}
	inline void set_red(int val)
	{
		m_red = validate_color(val);
	}
	inline void set_green(int val)
	{
		m_green = validate_color(val);
	}
	inline void set_blue(int val)
	{
		m_blue = validate_color(val);
	}
	inline void set_alpha(int val)
	{
		m_alpha = validate_color(val, 255);
	}
private:
	int m_red;
	int m_green;
	int m_blue;
	int m_alpha;

	static int validate_color(int param, int else_val = 0)
	{
		return (param >= 0 && param <= 255) ? param : else_val;
	}
};
Last edited on
How about
1
2
3
struct RGBA{
    unsigned char r, g, b, a;
};
?
Why unsigned char? Wouldn't that require casting to int? Also, what if a letter is passed to a constructor, eg 'a'

BTW: operators:
1
2
3
4
5
6
7
8
9
10
11
friend bool operator==(const RGBA& self, const RGBA& other)
{
	return other.get_red() == self.get_red() &&
	other.get_green() == self.get_green() &&
	other.get_blue() == self.get_blue() &&
	other.get_alpha() == self.get_alpha();
}
friend bool operator!=(const RGBA& self, const RGBA& other)
{
	return !(self == other);
}
Last edited on
Wouldn't that require casting to int?
No, unsigned chars are implicitly convertible to all other integer types.

Also, what if a letter is passed to a constructor
Letters are valid colors, since colors are numbers and letters are numbers. You can pass letters to the constructor of your RGBA class. Go ahead, try it.

BTW: operators:
1
2
3
4
5
6
7
8
9
struct RGBA{
    unsigned char r, g, b, a;
    bool operator==(const RGBA &other) const{
        return r == other.r && g == other.g && b == other.b && a == other.b;
    }
    bool operator!=(const RGBA &other) const{
        return !(*this == other);
    }
};
Use (signed) int in the interface.

Using unsigned char to limit the range of values passed to a function makes the code far less robust.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
#include <cassert>
#include <limits>

static_assert( std::numeric_limits<unsigned char>::max() == 255, "unexpected range for unsigned char" ) ;

void poor_style( unsigned char a ) // invariant: 0 <= a <= 255
{
    assert( a >= 0 && a <= 255 ) ; // meaningless
    // *** warning: comparison is always true due to limited range of data type

    std::cout << "poor_style( " << int(a) << " )\n" ;
}

int main()
{
    int value ;
    std::cin >> value ; // 428 or -45
    
    // requires validation by user code to avoid a silent logical error
    poor_style(value) ; // this val;idation would be required at every place in user code where the function is called
}


Even in the implementation, unless space is of paramount importance, consider using (signed) int
Evaluation of (most) expressions would require the implicit conversion (promotion) of unsigned char to int.
Topic archived. No new replies allowed.