Technically, what you did here does entail undefined behavior. However, because your getNum method is not virtual and makes no use whatsoever of this, it happens not to crash this time. To see why, imagine that the compiler internally rewrote your program like so:
class A { };
int A_getNum(A* this) { return 1234; }
int main()
{
A* pA = 0;
std::cout << A_getNum(pA) << '\n';
}
You can see that the null pointer is never dereferenced even though there is no actual A object, so it doesn't crash. The shared_ptr is irrelevant -- you'd get the same effect if you'd used a bare pointer.
If you want to force shared_ptr to crash you whenever -> is used on a null pointer, um, I don't believe there's anything standard. Your compiler may have a debugging option you can turn on, though -- for instance, if I compile your program with gcc 4.5 and -D_GLIBCXX_DEBUG, I get
$ ./a.out
/usr/include/c++/4.5/bits/shared_ptr_base.h:710:
_Tp* std::__shared_ptr<_Tp, _Lp>::operator->() const
[with _Tp = A, __gnu_cxx::_Lock_policy _Lp = (__gnu_cxx::_Lock_policy)2u]:
Assertion '_M_ptr != 0' failed.
Aborted
Can't help you with MSVC, sorry.