Should I avoid casting between data types?
I haven't really seen much about the use of this, but it seems like one of those last-minute-no-way-around kind of methods... but, for example, how would I use the length of a string in a for loop? The length property of a string is size_t, and if I had an integer i in a loop, how could I do that?
Where would casting be useful? Where should I avoid it? What are other methods of dealing with different data types that are better than cast?

First, the compiler will provide a warning (not error. Warnings are not fatal) for not casting between int and size_t... but there is no harm in doing either for (int i=0; i <(int)somestring.length(); i++) or for (size_t i=0; i < somestring.length(); i++) { . There is nothing wrong with casting... but you need to understand the implications in so doing.... what happens if you cast a float to an int? What about an int to a float? Is upcasting an inheritance tree ok? Just out of curiosity, if you didn't have casts, how could you make use of a void pointer? My point here, is that casting has very valid and useful purposes, but you must absolutely know what happens to the data when you do it.

Should I avoid casting between data types?

As a general rule, yes you should.

I haven't really seen much about the use of this, but it seems like one of those last-minute-no-way-around kind of methods... but, for example, how would I use the length of a string in a for loop? The length property of a string is size_t, and if I had an integer i in a loop, how could I do that?

An implicit conversion exists between int and size_t so, in rough terms, you shouldn't need an explicit conversion between them.

Note "explicit conversion" is actually the more correct name for a "cast".

In practice, the conversion can lose information (signed to unsigned, and different variable sizes), so several compilers will emit a warning when doing that conversion. If (and I repeat if) you know that conversion is valid, you can safely ignore the warning messages. If you can't tolerate warning messages from compilers, then an explicit conversion generally has the side effect of stopping the compiler complaining. That has the disadvantage that it also stops the compiler from emitting complaints that you should really address properly.

However, if you can guarantee the conversion is safe (i.e. you know that the value of the size_t variable can be stored in an int) a technique is;

size_t end = whatever();
   for (int i = 0; i < (int)end; ++i)

Where would casting be useful?

Explicit conversions are useful when you know a conversion is safe and the compiler considers the conversion erroneous (i.e. it emits and error message and refuses to continue) or suspicious (i.e. it emits a warning message, even if continues to compile).

An example is that, in C++, it is necessary to convert the return from malloc() to a pointer of an appropriate type. While it is usually better to employ operator new instead, an explicit conversion can be a simpler way. The flip side of this conversion is that it can also be used to permit an invalid conversion: for example, the return from malloc() shouild never be converted to a pointer to a non-POD class (in rough terms, a non-POD class is a class that has declared constructors, assignment operators,a destructor, or any virtual function).

An explicit conversion is also useful - rarely - to resolve ambiguity. Such ambiguity can occur with C++ classes that supply multiple conversion operations. [The better strategy is to ensure that no class supports multiple conversions].

Where should I avoid it?

As I said above, you should avoid it whenever possible. Where practical, an alternative should be found. The explicit conversion needs to be viewed as an absolute last resort.

What are other methods of dealing with different data types that are better than cast?

Generally, it comes down to design.

Instead of using the C malloc() function, use C++'s operator new.

Avoid writing classes that support multiple conversion operations (eg operator SomeType() members). Instead, write functions that the programmer must explicitly call to do the required (and intended) conversion. This is the reason, for example, that std::string supports the c_str() member function and does not support a direct conversion to (const char *).

In C++, make use of the _cast<> operators (const_cast, static_cast, dynamic_cast, reinterpret_cast) if you really have to, and avoid the C-style cast. And avoid using the _cast<> operators as well, if at all practical.

As a rough rule, you should never need to perform an explicit conversion from a base class to a derived class (or conversion of such pointers or references). The need to do this can, almost always, be eliminated by careful class design. For example, the base class probably needs to be polymorphic (i.e. provide virtual functions that can be over-ridden by the derived classes).

what's the difference between an explicit conversion and an implicit conversion?
By what means can a class "Support" a direct conversion? Does this mean I couldn't go if(a string==a char*){ , but I could still cast it? or could I cast it?
I think what I'm asking is (I'm just trying to understand how data-types work in C++) if I wrote a class, how would I deal with what it can and can't be converted to?

Also, what does string::c_str() do? Is it just a function that returns a const char*?

Thanks for your help so far btw... I'm starting to understand a lot more about this

oh, what WOULD happen if you casted a float to an int? Just lose the decimal places? Or a signed to unsigned or vice versa?

An explicit conversion is what you're calling a cast. An implicit conversion is a conversion between types that the compiler allows or performs, even if you don't do a cast. For example;

int i = 3;
   long j = i;

The initialisation of j involves an implicit conversion of an int to a long. The compiler knows how to do that, so it happens implicitly (as far as the programmer is concerned).

Conversion between basic types are built in: for example, the compiler knows how to add an int to a double.

Class types support conversions in two ways: by the constructors they supply, and by operator functions.

class X
       X(const char *);

allows a const char pointer to be converted to an X. Given a function;

void func(const X &);

the call


will create a temporary X by passing "Hello" to its constructor, and then pass that temporary to func(). That process of creating the temporary X from "Hello" is a conversion.

The other way is that;

class Y

         operator const char *() const;  // conversion to const char *

declares an operator that allows a Y to be converted to a const char *. So, given;

void another_func(const char *);

it is possible to do this;

Y y;   / assume we have a default constructor

as the compiler will implicitly invoke the operator const char *() for the object y, and pass the result to another_func().

Because of all that, you control the conversions supported by a class by controlling what constructors it supports and what conversion operators it supports. Constructors can be used to do conversions. However, prefixing the constructor keyword to the constructor declaration prevents it from being used to do implicit conversions (and some other things).

std::string::c_str() returns a const char *. However, std::string does not supply an operator const char *().

Converting a float to an int rounds towards zero. That involves dropping the decimal places for small values. However, that doesn't work for larger values. For example, assume your compiler supports a 32 bit float and a 32 bit int (fairly commonly true). The float can represent the value 3.4E+30. What would you expect to happen if you convert that value to an int (which can only hold values in the range -2,147,483,648 to 2,147,483,647)?