The fear of the LORD is the beginning of wisdom, and knowledge of the Holy One is understanding.
Tuesday, May 20, 2014
C#: Difference between int.Parse() and Convert.ToInt32
If you've got a string, and you expect it to always be an integer (say, if some web service is handing you an integer in string format), you'd use Int32.Parse().
If you're collecting input from a user, you'd generally use Int32.TryParse(), since it allows you more fine-grained control over the situation when the user enters in invalid input.
Convert.ToInt32() takes an object as its argument, and I believe it invokes Int32.TryParse() when it finds that the object taken as the argument is a string.
Convert.ToInt32 also does not throw ArgumentNullException when it's argument is null the way Int32.Parse() does. That also means that Convert.ToInt32() is probably a wee bit slower than Int32.Parse(), though in practice, unless you're doing a very large numbers of iterations in a loop, you'll never notice it.
Monday, May 12, 2014
C++ New virtual function controls: override, final, default, and delete
Reference http://www.learncpp.com/cpp-tutorial/b-6-new-virtual-function-controls-override-final-default-and-delete/
override
override
When working with derived classes, it’s fairly easy to inadvertently create a new virtual function in the derived class when you actually meant to override a function in the base class. This happens when you fail to properly match the function prototype in the derived class with the one in the base class. For example:
1
2
3
4
5
6
7
8
9
10
11
| class Base { virtual void A( float =0.0); virtual void B() const ; }; class Derived: public Base { virtual void A( int =0); // specifies parameter as int instead of float, treated as new function virtual void B(); // specifies function as non-const, treated as new function }; |
When this happens, it’s can be easy to make a function call to A() or B() and expect to get the derived version but end up getting the base version instead.
This phenomena can also easily occur when you add a new parameter to a function in Base but forget to update the version in Derived. When that happens, the function that was an override in Derived is no longer an override, and your code mysteriously stops working. These kinds of problems can be hard to find because the change that triggers them is so innocuous looking.
C++11 introduces a new identifier called override that allows you to explicitly mark functions you intend to be overrides. If the function is not an override, the compiler will complain about it. For example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| class Base { virtual void A( float =0.0); virtual void B() const ; virtual void C(); void D(); }; class Derived: public Base { virtual void A( int =0) override; // compile error because Derived::A(int) does not override Base::A(float) virtual void B() override; // compile error because Derived::B() does not override Base::B() const virtual void C() override; // ok! Derived::C() overrides Base::C() void D() override; // compile error because Derived::D() does not override Base::D() }; |
Although use of the override identifier is not required, it is highly recommended, as it will help prevent inadvertent errors.
(If you’re wondering why this was implemented as an identifier rather than a keyword, I presume this was done so that the name “override” can be used as a normal variable name in other contexts. If it had been defined as a keyword, it would be reserved in all contexts, which might break existing applications)
final
There are occasionally times when you don’t want to allow someone to override a virtual function, or even create a derived class. C++11 adds the identifier final to provide this functionality.
The following example shows the use of the final identifier to make a function non-overrideable:
1
2
3
4
5
6
7
8
9
| class Base { virtual void A() final; // final identifier marks this function as non-overrideable }; class Derived: public Base { virtual void A(); // trying to override final function Base::A() will cause a compiler error }; |
The final identifier can also be used on classes to make them non-inheritable:
1
2
3
4
5
6
7
| class Base final // final identifier marks this class as non-inheritable { }; class Derived: public Base // trying to override final class Base will cause a compiler error { }; |
There are some legitimate reasons to make functions or classes final. For example, the most common use of final is to ensure that an immutable class stays immutable. An immutable class is a specially-designed class whose state cannot be modified after it is created. Without the final identifier, a derived class could add functions that could cause the class to become mutable. If the base class is made final, it cannot be subclasses, and this is avoided.
However, generally speaking, unless you have a really good reason, use of final should generally be avoided. And if you do use the final keyword, document why, as it will likely not be obvious to whomever inherits your code.
default
By default, C++ will provide a default constructor, copy constructor, copy assignment operator (operator=) and a destructor. If you provide alternate versions of any of these functions for your class, C++ will not provide a default version. However, in C++11, you can now specify that you would like the compiler to provide a default one anyway. This is done by prototyping the function and using the default specifier:
1
2
3
4
5
| class Foo { Foo( int x); // Custom constructor Foo() = default ; // The compiler will now provide a default constructor for class Foo as well }; |
The default specifier can only be used with functions that have a default.
delete
More useful than the default specifier is the delete specifier, which can be used to disallow a function from being defined or called. One of the best uses of the delete specifier is to make a class uncopyable:
1
2
3
4
5
| class Foo { Foo& operator=( const Foo&) = delete ; // disallow use of assignment operator Foo( const Foo&) = delete ; // disallow copy construction }; |
The delete specifier can also be used to make sure member functions with particular parameters aren’t called. For example:
1
2
3
4
5
| class Foo { void Foo( long long ); // Can create Foo() with a long long void Foo( long ) = delete ; // But can't create it with anything smaller }; |
In the above example, if you try to call Foo with a char, short, int, or long, those will all get implicitly converted to a long, which will then match Foo(long). Since Foo(long) has been deleted, the compiler will error.
If you want your class to only be called with very specific data types, you can turn off implicit conversions altogether by using a templated function to match everything that isn’t defined explicitly:
1
2
3
4
5
| class Foo { void Foo( long long ); // Can create Foo() with a long long template < typename T> void Foo(T) = delete ; // But can't create it with anything else }; |
Subscribe to:
Posts (Atom)