Pergunta

I need to create constructor taking two integers as arguments.

From there I need to call method taking these integers by reference. Inside this method I should dynamically convert integers into char* type (array of digits).

At the end of the constructor I should have two char* arrays instead of initial integers.

I kind of have to do it this way because the other class does the same thing but on structures. And save them into the template attributes.


I'm new to c++ language but my first guess was to use templates. I did a little research on the topic and found out it should work.

I'd love to compile the whole thing myself, but the mess with implementing c++ classes in my head produces quite long list of compile errors.


First question - can this be done using templates? Second question, because I've already written something by myself:

template <class type> class Addition {
   type num_a;
   type num_b;
   void convert(type, type);
public:
   Addition(type, type);
}

template <class type> Addition::Addition(type a, type b) {
   convert(&a, &b);
   num_a = a;
   num_b = b;
}
template <class type> Addition::convert(type *a, type *b) {
   int temp_a = a, temp_b = b;
   a = char[256], b = char[256];
   // converting
}

Is this o.k., or did I do something wrong?
Do you have any suggestions about the way I implement classes in c++?

Why can't I initialize attribute with a value, like:

template <class type> class Addition {
   type outcome = 0;
}

And if there's no need to use this keyword in c++, how do I do something like this?:

template <class type> Addition::Foo(type a, type b) {
   this->a = a; // a = a;
   this->b = b; // b = b;
}
Foi útil?

Solução

Disclaimer: I cannot judge wheter you really need templates for what you are doing. That would depend on the number of different types that you want your Adddition class template to work with. If you will only use it for int, then perhaps this will introduce unnecessary complexity. You can always refactor later (this would be the Agile approach).

Having said that, if you want to use templates, the usual convention is to write T for a template parameter, and to use type for a nested typedef inside a class template. Using typename or class is a matter of taste, but typename stresses the fact that builtin types can also be passed as arguments. Note however that with template-template parameters you would need to write

template<template<typename> class U> SomeClass { /* your definition */ };
                            ^^^^^ // <-- NOT typename here 

which stresses the fact that only class templates can be passed as arguments.

There are a few other nitpicks that one could mention about your code that would make it fail to compile (missing return type in convert() and missing semi-colon in class definition):

template <typename T> 
class Addition 
{
   static const std::size_t N = 256; // are you sure that 256 is all you'll ever need?
   T num_a;
   T num_b;
   void convert(T const*, T const*); // by T const*, not T*
public:
   Addition(T const&, T const&); // by T const&, not T
}; // <-- make sure to end class definitions with a semi-colon!

template <typename T> 
Addition::Addition(T const& a, T const& b) 
{
   convert(&a, &b);
   num_a = a;
   num_b = b;
}

template <typename T>
void Addition::convert(T const* a, T const* b) // <-- use T const* if you don't modify the parameters
^^^^ // <-- you forgot the return type
{
   int temp_a = a, temp_b = b;
   a = char[N], b = char[N]; <-- hardcoded 256 is bad practice, better to keep that in 1 place only
   // converting
}

In C++11 you can even use delegating constructors (supported by latest Visual C++ and of course gcc/Clang) and write

template <typename T> 
Addition::Addition(T const& a, T const& b) 
:
    Addition(&a, &b) // delegate to the other constructor
{}

template <typename T>
Addition::Addition(T const* a, T const* b) // <-- use T const* if you don't modify the parameters
{
   int temp_a = a, temp_b = b;
   a = char[N], b = char[N]; <-- hardcoded 256 is bad practice, better to keep that in 1 place only
   // converting
}

Finally, because template definition have to be in headers anyway, you could even write everything inside the class definition like this:

template <typename T> 
class Addition 
{
   static const std::size_t N = 256; // are you sure that 256 is all you'll ever need?
   T num_a;
   T num_b;

   Addition(T const*, T const*) // by T const*, not T*
   {
      int temp_a = a, temp_b = b;
      a = char[N], b = char[N]; 
      // converting
   }
public:
   Addition(T const&, T const&) // by T const&, not T
   :
       Addition(&a, &b) // delegate to the other constructor
   {} 
}; // <-- make sure to end class definitions with a semi-colon!

This saves you from tediously writing both declarations and definitions of all the member functions. For short and sweet classes (which you should strive for anyway) this is the preferred way of writing templates, but for very long definitions you might want to separate the declaration and definition.

Finally, as was explained by @tacp, you really need to use this->a to disambiguate a class data member from a function parameter. For that reason, people often write data members with a trailing underscore or a m_ prefix.

Outras dicas

For your latter questions:

template <class type> class Addition {
  //type outcome = 0; 
  //^^^^you have to call default constructor of type
  type outcome = type();
}

It is better to use typename for convention, using class is also OK.

template <class type> Addition::Foo(type a, type b) {
   this->a = a; // a = a;
   this->b = b; // b = b;
}

If the passed parameter and member has the same name, you need to use this. You cannot do

a =a;
b =b;

since a,b are in local scope, but this->a means class member a.

Since you always want to convert integers to char array, I don't think you really need templates. Unless you would like convert double, float and other types into char* also in the future. I have not looked all the issues, so there may be others remain.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top