zell
zell

Reputation: 10204

C++'s double colon used after a class name instead of a namespace

I am trying to understand a c++ program listed here. I am confused about the second use of double colons on lines 86-87:

 using TransformType = itk::AffineTransform< ScalarType, Dimension >;
 TransformType::Pointer transform = TransformType::New();

It looks like TransformType is a user-defined type. How would one use it before New()? I heard that the double-colon is to be used following a namespace, but here, TransformType is a type (namely class) rather than a namespace. Can someone clarify --- should double colon be always used after a namespace in C++? Would it possible to use a dot (like in Java) instead?

Upvotes: 3

Views: 1090

Answers (1)

Lightness Races in Orbit
Lightness Races in Orbit

Reputation: 385325

You use the scope resolution operator (::) to name something in a namespace, or in a class, or in a scoped enum; this is called qualified lookup.

#include <iostream>

namespace N
{
   int x = 0;
}

int main()
{
   std::cout << N::x << '\n';
}

Using it with a class usually means you're referring to some static member, because otherwise you'd generally be using objectInstance.member instead.

#include <iostream>

class C
{
public:
   static int x;
}

int C::x = 0;

int main()
{
   std::cout << C::x << '\n';
}

Though, within a non-static member function, there are still uses for ::, such as disambiguating between names that exist concurrently in different bases.

class Base
{
public:
   void foo() {}
};

class Derived : public Base
{
public:
   void foo()
   {
      // Do base version (omitting Base:: will just call this one again!)
      Base::foo();

      // Now maybe do other things too
   }
};

int main()
{
   Derived obj;
   obj.foo();
}

… or for naming a non-static member in a scenario where an object context is not required:

#include <iostream>

class C
{
public:
   int x;
}

int main()
{
    std::cout << sizeof(C::x) << '\n';

    decltype(C::x) y = 42;
}

It's needed with scoped enums because, well, they're scoped; that's the whole point of them. They don't leak into the surrounding scope but have their own which as a result you need to specify specifically.

enum class E
{
   Alpha,
   Bravo,
   Charlie
};

void foo(E value) {}

int main()
{
   foo(E::Alpha);
}

Some languages let you access static members of classes with the type name followed by ., just like you'd access non-static members of classes with the object name followed by .. C++ is not one of those languages.

By the way, this is legal:

#include <iostream>

class C
{
public:
   int x = 42;
};

int main()
{
   C obj;
   std::cout << obj.C::x << '\n';
//                  ^^^ what?!
}

Adding scope resolution to x here is not necessary, because the language already knows from the obj. that you're asking for a member of a class C. But you can still add it if you want. It's just usually "done for you" in this case.

Upvotes: 7

Related Questions