Scope resolution :: woes

This is a sample program that teaches us unions & structs. Structs are public access-specifiers by default, so why do I need :: the scope resolution operator when referring to the enum & not the union within the struct?

myData2.value.alphabet = 'x'; //This is OK, no :: needed

myData1.Type = ComplexType::Int;//Why :: needed & not just "...ComplexType.Int;"
//myData1.Type = myData1.DataType::Int;//works too, why not myData1.DataType.Int
//myData1.Type = myData1.DataType.Int; //Does not work, why?

Many cases where sometimes () are needed & other times just use "." instead of :: it just ends up confusing. I have to find more examples from previous sample programs.

//On another note why is this "()" needed in this class pointer?
MyClass* MyClass1 = new MyClass();
//It is a class, why () needed? I understand [] needed for array pointers, but this is a class?


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <iostream>
using namespace std;

struct ComplexType
{
	enum DataType
	{
		Int,
		Char
	} Type;
	
	union Value
	{
		int num;
		char alphabet;
		
		Value(){}
		~Value(){}
	} value;
};

void DisplayComplexType (const ComplexType& obj)
{
	switch (obj.Type)
	{
		//case obj.DataType::Int:	//works too
		case ComplexType::Int:
			cout << "num = " << obj.value.num << endl;
			break;
		case ComplexType::Char:
			cout << "Char =" << obj.value.alphabet << endl;
			break;
	}
}

int main()
{
	ComplexType myData1, myData2;
	//myData1.Type = myData1.DataType::Int;		//works too
	myData1.Type = ComplexType::Int;
	myData1.value.num = 2017;
	
	myData2.Type = ComplexType::Char;
	myData2.value.alphabet = 'x';
	
	DisplayComplexType (myData1);
	DisplayComplexType (myData2);
		
	return 0;
}
Last edited on
It says on this reference site: https://en.cppreference.com/w/cpp/language/enum#Using-enum-declaration
that the following should be legal code as of c++11:
1
2
3
4
5
6
7
8
9
10
11
struct X
{
    enum direction { left = 'l', right = 'r' };
};
X x;
X* p = &x;
 
int a = X::direction::left; // allowed only in C++11 and later
int b = X::left;
int c = x.left;
int d = p->left;

Line 10 of which is similar to what you seem to be wanting.

If you're getting build errors, then it's your compiler that's out of date. It should be noted that cplusplus.com's site compiler at cpp.sh is out of date, which gets annoying when you want to test things like that out.
Last edited on
myData1.Type = myData1.DataType.Int; //NOT ALLOWED

It says...."Type name is not allowed" & "Error C7624 Type name 'ComplexType::DataType' cannot appear on the right side of a class member access expression"


I tried it on Visual Studio & Embarcadero Dev C++ v6.3.
I just installed Visual Studio a few days ago....

Microsoft Visual Studio Community 2019
Version 16.10.4
VisualStudio.16.Release/16.10.4+31515.178
Microsoft .NET Framework
Version 4.8.04084

Installed Version: Community

Visual C++ 2019 00435-60000-00000-AA811
Microsoft Visual C++ 2019

C# Tools 3.10.0-4.21329.37+246ce641f04b67ef017655275d850bf902a8e40f
C# components used in the IDE. Depending on your project type and settings, a different version of the compiler may be used.

Microsoft Visual C++ Wizards 1.0
Microsoft Visual C++ Wizards

Microsoft Visual Studio VC Package 1.0
Microsoft Visual Studio VC Package

Mono Debugging for Visual Studio 16.10.15 (552afdf)
Support for debugging Mono processes with Visual Studio.
Structs are public access-specifiers by default, so why do I need :: the scope resolution operator when referring to the enum & not the union within the struct?
:: and . has nothing to do with accessibility of the member in question. :: is used to access types declared inside types and static members of a class, while . is used to access non-static members, which require an object to access them.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
struct A{
    int a;
    static int b;
    struct C{};
};

A::a;   //Invalid. a exists only within specific instances of A.
A.a;    //Invalid. The thing on the left side of . must be an object.
A().a;  //Valid. This creates a temporary instance of A and accesses its a.
A()::a; //Invalid. The thing on the left side of :: must be a namespace or type.
A x;
x.a;    //Valid.
x::a;   //Invalid. The thing on the left side of :: must be a namespace or type.

A::b;   //Valid.
A.b;    //Invalid. The thing on the left side of . must be an object.
A().b;  //Valid (if I'm not mistaken).
A()::b; //Invalid. The thing on the left side of :: must be a namespace or type.
x.b;    //Valid (if I'm not mistaken).
x::b;   //Invalid. The thing on the left side of :: must be a namespace or type.

A::C;   //Valid.
A.C;    //Invalid. The thing on the left side of . must be an object.
A().C;  //Invalid. Types within namespaces or classes cannot be access via .
A()::C; //Invalid. The thing on the left side of :: must be a namespace or type.
x.C;    //Invalid. Types within namespaces or classes cannot be access via .
x::C;   //Invalid. The thing on the left side of :: must be a namespace or type. 

As for your particular question, unions work like non-static members, so they must be accessed via the dot operator, while enums count as types, so they must be access via ::. There's no particular reason why it's this way, it's just how the language is designed. In fact in Java and C# the :: operator doesn't exist and . is used for everything.

//On another note why is this "()" needed in this class pointer?
MyClass* MyClass1 = new MyClass();
//It is a class, why () needed? I understand [] needed for array pointers, but this is a class?
As long as you don't need to pass anything to the constructor, you can omit the parentheses when allocating instances of classes:
 
auto MyClass1 = new MyClass;
Note that you should avoid using new and naked pointers if possible.
Last edited on
Thanks, makes more sense now & now I just have to get used to it. I reached chapt 11, Polymorphism & no detailed explanation as you have provided as of yet.

When you say "must be a namespace" you mean the name of functions/methods/classes & names of types & variables?
When you say "must be a namespace" you mean the name of functions/methods/classes & names of types & variables?
No, namespaces are distinct constructs in C++. E.g.
1
2
3
4
5
6
7
8
9
namespace my_functions{

void foo();

}

//...

my_functions::foo();
They're used to organize declarations hierarchically and to avoid name collisions.
Topic archived. No new replies allowed.