1

following class ADate is declared enclosed by namespace A
.h file

#ifndef ADATE_H
#define ADATE_H

namespace A{

    class ADate
    {
    public:
        static unsigned int daysInMonth[];

    private:
        int day;
        int month;
        int year;

    public:
        ADate(const unsigned int day, const unsigned int month, const unsigned int year);
    };

    bool isValidDate(const unsigned int day, const unsigned int month, const unsigned int year);
}


#endif // ADATE_H

.cpp file:

#include "adate.h"

using namespace A;

unsigned int ADate::daysInMonth[12] = { 31,28,31,30,31,30,31,31,30,31,30,31 };

ADate::ADate(const unsigned int day, const unsigned int month, const unsigned int year) :
    day{day},
    month{month},
    year{year}
{
    if(!isValidDate(day,month,year)){
        throw string{"invalid Date"};
    }
}

bool isValidDate(const unsigned int day, const unsigned int month, const unsigned int year)
{
    if(month < 1 || month > 12){
        return false;
    }
    if(day < 1 || day > ADate::daysInMonth[month-1]){
        return false;
    }
    if(year < 1979 || year > 2038){
        return false;
    }
    return true;
}

One should think that the code above can be compiled successfully. However, this is not that way, cause an undefined reference to `A::isValidDate(unsigned int, unsigned int, unsigned int)' occurs.

I don't understand why I have to use the namespace-specifier as prefix for the global function 'isValidDate'.

Can you explain why. Thank you

wuarmin
  • 3,274
  • 3
  • 18
  • 31
  • 10
    Please stop using `using namespace std;` in header files. Further reading: [Why is “using namespace std” in C++ considered bad practice?](http://stackoverflow.com/questions/1452721/why-is-using-namespace-std-in-c-considered-bad-practice) – NathanOliver Apr 22 '16 at 18:26
  • [A recent question](http://stackoverflow.com/questions/36776051/how-to-overload-operator-from-within-namespace/36776101#36776101). – LogicStuff Apr 22 '16 at 18:29
  • Why does `ADate`'s constructor take regular `int`s, but `isValidDate` take `unsigned int`s? You're kinda begging for signed/unsigned issues. – Nicol Bolas Apr 22 '16 at 18:30
  • 3
    The prototype for function `isValidDate` is inside the namespace `A` in the header file, so it's really not global. – Unimportant Apr 22 '16 at 18:47
  • It works the same way as in the header `namespace A { ... }` – Thomas Apr 22 '16 at 19:04
  • 2
    Time for a code review (once you fix this bug). Checkout https://codereview.stackexchange.com – Martin York Apr 22 '16 at 20:12
  • I fixed the issues you mentioned. – wuarmin Apr 22 '16 at 20:52

1 Answers1

1

Because of the namespace lookup rules.

See: http://en.cppreference.com/w/cpp/language/lookup

For variables, namespaces, classes, etc (apart from functions), name lookup must produce a single declaration in order for the program to compile.

For functions name lookup can associate multiple declarations (which are then resolved by argument comparison).

So:

bool isValidDate(const unsigned int day, const unsigned int month, const unsigned int year)
{
   // CODE
}

Is both a declaration and a definition. The namespace resolution did not need to resolve the name of the function to the A::isValidDate() function so it does not. Instead it adds another declaration into the current scope for isValidDate().

Martin York
  • 257,169
  • 86
  • 333
  • 562
  • Ok, thank you for the explanation. Just for completeness: the member methods don't need the specifier, because of the class specifier of the class which was declared within the namspace. Is that correct? – wuarmin Apr 22 '16 at 20:50
  • @PaceyW. Correct the class name must be exactly resolved to a specific class (if multiple classes match this is a compile time error). Since there is now an exact match to the class you can match the definition to the declaration. – Martin York Apr 22 '16 at 20:53