constructor for class that contains another class and constructor C++

Started by
7 comments, last by Ravyne 9 years, 4 months ago

i have this:






template <class _cType> class t3dpoint {
        public:
_cType x;
_cType y;
_cType z;

t3dpoint<_cType>() : x(_cType(0.0)), y(_cType(0.0)), z(_cType(0.0))   //t3dpoint() : x(_cType(0.0) etc
{ }

 };

 

template <class _cType> class  t4dpoint : public t3dpoint<_cType> {

public:
_cType w;

 t4dpoint<_cType>() : x(0.0), y(0.0), z(0.0), w(1.0) <-- [BCC32 Error] DxcMath.h(282): E2312 't3dpoint<float>::x' is not an unambiguous base class of 't4dpoint<float>'
{ }

};

now i could change this to






t4dpoint<_cType>() { x = 0.0; y = 0.0; z = 0.0; w = 1.0;  return *this; }

but i rather stick to this implementation:






t4dpoint<_cType>() : x(0.0), y(0.0), z(0.0), w(1.0) 

any idea how to deal with this?

sorry about that code its this post editor fault

Advertisement
While I personally don't think what you are doing is a good idea, why are you trying to initialize members of the base class in the derived class? The base class is responsible for initializing them and it already does. Why are you trying to assign 0 to something which is already guaranteed to be 0?

That aside, please try to get better formatting for your code snippets. The extra newlines and randomized indentation caused me quite a bit of problems trying to understand what you are doing.

BitMaster cosider this:


t3dpoint<_cType>(_cType a, _cType b, _cType c) : x(_cType(a)), y(_cType(b)), z(_cType(c))
		{ }

t4dpoint<_cType>(_cType a1, _cType b, _cType c, _cType d) : x(_cType(a1)), y(_cType(b)), z(_cType(c)), w(_cType(d))
		{ }

this produces the same error

t4dpoint<float> color = t4dpoint<float>(1.0,1.0,1.0,1.0);

and that was acutally what i was about to ask

As BitMaster said, the base class is responsible for initializing itself. You don't initialize the base class from derived classes, but instead you delegate the work to it from the derived class' constructor.


template <class _cType> class  t4dpoint : public t3dpoint<_cType> {
public:
    _cType w;
 
    // the t3dpoint base class is automatically default initialized if not specified, and then initialize our own member
    t4dpoint<_cType>() : w(1.0)
    { }
 
    // initialize the t3dpoint base class and then initialize our own member
    t4dpoint<_cType>(_cType x, _cType y, _cType z, _cType w) : t3dpoint(x,y,z), w(w)
    { }
};

Either only initialise w in the t4dpoint class (base class is then default constructed) or call the base class constructor directly

t4dpoint<_cType>(_cType a, _cType b, _cType c, _cType d) : t3dpoint<_cType>(a, b, c), w(d) {}

should work...

EDIT: Which is what Brother Bob said as well. I'm not sure if my template argument is needed for base class constructor, I have it, Brother Bob does not. One or both of us is correct ;)

"Most people think, great God will come from the sky, take away everything, and make everybody feel high" - Bob Marley

thanks that worked

however i have another question:

if i have overloaded operator function in base clas

like




		t3dpoint<_cType> operator*(const _cType val) const
		{
			return t3dpoint<_cType>(x*val, y*val,z*val);
		}

will this get called when i will be using t4dpoint<double> p = t4dpoint<double>(1.0,0.0,0.0,0.0) * 3.0; ?

ok done it since t3dpoint<> * floating point returns t3dpoint<> i had to write:


		t4dpoint<_cType>& operator=(const t3dpoint<_cType>& in)
		{
			x = in.x;
			y = in.y;
			z = in.z;
			return *this;
		}

now it works thanks for help

I personally dont like having vector classes derive from each other in that way. A 4D vector is not a 3D vector, its more like the 3D vector is a special case of the 4D vector.
Its easy to add a conversion constructor for cases where you really want conversion without needing inheritance and prevents loosing w silently.
Additionally, the natural form of a vector is IMO an array, not a struct. This allows indexing and cuts down on repetition from having getX, getY, getZ, getW, getU, getV, getR, getG, getB, getA, ...

Btw., why dont you use a premade library like glm or others?

I personally dont like having vector classes derive from each other in that way. A 4D vector is not a 3D vector, its more like the 3D vector is a special case of the 4D vector.


Just to spell out that very good point:

Inheritance models an is-a relationship. When you inherit Derived from Base, you are saying that Derived is a Base. The language models that assumption all over the place, too; for instance, you'll be able to pass an instance of Derived to a function expecting a Base. In your case, that means a function that takes a t3point<float> will also implicitly take a t4dpoint<float>, which is almost certainly not desired.

If you're using inheritance as a hacky cut-n-paste, stop. That's not what it's for. That's not what it models. That's not how it works.

Sean Middleditch – Game Systems Engineer – Join my team!

Just to reinforce what others have said -- this is not a good use of inheritance -- Sean and Wintertime lay out the case against it nicely. Its better to have independent vector classes of the common small dimensions 2, 3, and 4, and a general-purpose compile-time/run-time sized vector for larger/arbitrary dimension if you need it.

What you've probably done is misidentified the nature of their shared interfaces and conflated it with a desire for code-reuse. That is, influenced by wanting to reuse the code of vector3, you have assumed that vector4 simply extends it. In reality, vector3 and vector4 do inherit a common interface, but that does not imply that one should inherit from the other -- conceptually they both inherit from a common interface that you have not defined. For completeness, also note that while there is a common interface, it is only a subset of the operations that apply to all vectors (e.g. the cross product only exists for vectors of sizes 3 and 7 (e.g. not for 4, which you are deriving from 3), and there is a psuedo-cross-product in 2 dimensions that's not correct in a mathematical sense but is sometimes useful nonetheless).

Now, before you go off an try to implement this common interface I've spoken of, stop, because its not an idea that's good to take literally. Firstly because the necessary virtual inheritence would kill performance, and secondly because you simply don't use vectors of different dimensions interchangeably very often -- almost never. In such cases, you should either be using that general-purpose runtime-sized vector to begin with, or alternatively a function template can be used to leverage duck-typing, which is essentially a loose, anonymous interface of the type you need here. In cases where they are not used interchangably, but where it seems beneficial to allow a vector4 to act as a vector3 temporarily, its better to provide a conversion operator and/or a vector3 constructor that takes a vector4. Note that when going from a lower to a higher dimension vector you need to be explicit about what the missing coordinate (e.g. W) should be assigned to.

throw table_exception("(? ???)? ? ???");

This topic is closed to new replies.

Advertisement