I am seeking to learn C++. I am using the complex base class as source for this learning, by trying to adapt it to a template class. I am calling this class "plexmath". My effort follows ,but does not compile. I would like to retain the "protected" status of the variables "real" and "imag", and need to declare the Get_Real and Get_Imag functions so as to permit recall of the imaginary parts of the complex number as friend functions to do so. Unfortunately, I am having some trouble getting the syntax right by which to declare a template friend function that returns the templatized variable "whatever". Any suggestions would be very much appreciated.

Thanks!

Template Class (non-working) follows:

template <class whatever> class plexMath
{
protected:
whatever real;
whatever imag;
public:
// creates plexMath number
plexMath(whatever,whatever);
plexMath();
~plexMath()
{
}
friend whatever Get_Real(plexMath<whatever>);
friend whatever Get_Imag(plexMath<whatever>);
};


template <class whatever> plexMath<whatever>::plexMath(whatever thisreal, whatever thisimag)
{
real = thisreal;
imag = thisimag;
}


template <class whatever> plexMath<whatever>::plexMath()
{
}


template <class whatever> whatever Get_Real(plexMath<whatever> anum)
{
return anum.real;
}


template <class whatever> whatever Get_Imag(plexMath<whatever> anum)
{
return anum.imag;
}

Edited 3 Years Ago by pyTony: fixed formating

This will work until you try to do just about anything else.

#include <iostream>

using namespace std;

template <typename T>
class Complex {
protected:
  T real, imag;
public:
  Complex(T real_init, T imag_init)
    : real(real_init), imag(imag_init)
  {}
public:
  template <typename U> friend U get_real(Complex<U>& c);
  template <typename U> friend U get_imag(Complex<U>& c);
};

template <typename U>
U get_real(Complex<U>& c)
{
  return c.real;
}

template <typename U>
U get_imag(Complex<U>& c)
{
  return c.imag;
}

int main()
{
  Complex<int> a(1, 2);

  cout<< get_real(a) <<endl;
  cout<< get_imag(a) <<endl;
}

Now:

>I would like to retain the "protected" status of the variables "real" and "imag"
Why? Protected data is evil, and it should be avoided at all costs. With only a few exceptions, all data members should be private, otherwise they should be public. Forget that you can make them protected.

Thanks again. I did get it working yesterday by coding the functions in-line (right word? - meaning within the body of the class declaration). This response is very much appreciated, as it does establish that I don't have to code friend template functions in-line, instead of merely using a prototype (right word again? - meaning the reference to a function associated with a class located within the class) in the class declaration and the function description later.

There are two more questions brought up by the response I received:

1. Why is it necessary to put the "&" after the <Complex U> type statement? (Is this the only way to code a friend template function if one is passing a new class type declared within the class with which the friend template function is associated? Would the "&" be necessary if I were passing an "int" or "double" instead, as with "int& c" or "double& c"?)

2. Why are "protected" variables "evil"? (The word "protected" usually has a positive context.)

I realize I'm asking a lot of questions, and have been surprised (and quite pleased) by the quality and consistency of the responses. You have my sincerest thanks.
-----------------------------

This will work until you try to do just about anything else.

#include <iostream>

using namespace std;

template <typename T>
class Complex {
protected:
  T real, imag;
public:
  Complex(T real_init, T imag_init)
    : real(real_init), imag(imag_init)
  {}
public:
  template <typename U> friend U get_real(Complex<U>& c);
  template <typename U> friend U get_imag(Complex<U>& c);
};

template <typename U>
U get_real(Complex<U>& c)
{
  return c.real;
}

template <typename U>
U get_imag(Complex<U>& c)
{
  return c.imag;
}

int main()
{
  Complex<int> a(1, 2);

  cout<< get_real(a) <<endl;
  cout<< get_imag(a) <<endl;
}

Now:

>I would like to retain the "protected" status of the variables "real" and "imag"
Why? Protected data is evil, and it should be avoided at all costs. With only a few exceptions, all data members should be private, otherwise they should be public. Forget that you can make them protected.

>Why is it necessary to put the "&" after the <Complex U> type statement?
You should pass objects by value only when you have a very good reason. When you pass by value, the copy constructor is called, and more storage is typically used (in the case of objects), often for little or no benefit. Also, in the example, c should really be passed by const reference since no changes are being made to the object.

>Why are "protected" variables "evil"?
Because they break encapsulation. If your base class has protected data members then anyone can inherit from it and fiddle with them directly. That's the same as making them public. Allowing protected data members was a mistake that Bjarne Stroustrup readily admits to. The general rule of thumb is that if any of your data is private, all of your data should be private. You can then use protected member functions (which are okay) to act as the safe interface for derived classes.

This article has been dead for over six months. Start a new discussion instead.