What Is the Meaning of This Star (*) Symbol in C++? - Pointer to Member

What is the meaning of this star (*) symbol in C++? -- Pointer to member

::* denotes a Pointer to member.

With the surrounding code it's actually a Pointer to member function.

Status_e(MyClass::*)(TupleInfo & info)

is a member function of class MyClass, returning Status_e, and having one parameter TupleInfo&. (The argument name info is useless here but obviously silently ignored by the compiler.)

The other snippet in OP's question shows how to call it:

status = (this->*m_processObjects[f])(m_tuples[i]);

Storing a method pointer would look like this:

std::vector<Status_e(MyClass::*)(TupleInfo & info)> m_processObjects;

...

m_processObjects.push_back(&MyClass::aMethod);

Of course, the signature of MyClass::aMethod must match.

A simplified sample to demonstrate it:

#include <iostream>
#include <vector>

class Test {

private:
std::vector<int(Test::*)(const char*)> _tblTestFuncs;
public:
Test()
{
_tblTestFuncs.push_back(&Test::func1);
_tblTestFuncs.push_back(&Test::func2);
_tblTestFuncs.push_back(&Test::func3);
}

int func1(const char *caller) { std::cout << "Test::func1 called from '"<< caller << "': "; return 1; }
int func2(const char *caller) { std::cout << "Test::func2 called from '"<< caller << "': "; return 2; }
int func3(const char *caller) { std::cout << "Test::func3 called from '"<< caller << "': "; return 3; }

void call()
{
for (size_t i = 0, n = _tblTestFuncs.size(); i < n; ++i) {
int result = (this->*_tblTestFuncs[i])("Test::call()");
std::cout << "Return: " << result << '\n';
}
}
};

int main()
{
Test test;
// test method vector in main()
std::vector<int(Test::*)(const char*)> tblTestFuncs;
tblTestFuncs.push_back(&Test::func1);
tblTestFuncs.push_back(&Test::func2);
tblTestFuncs.push_back(&Test::func3);
for (size_t i = 0, n = tblTestFuncs.size(); i < n; ++i) {
int result = (test.*tblTestFuncs[i])("main()");
std::cout << "Return: " << result << '\n';
}
// test method vector in Test
test.call();
// done
return 0;
}

Output:

Test::func1 called from 'main()': Return: 1
Test::func2 called from 'main()': Return: 2
Test::func3 called from 'main()': Return: 3
Test::func1 called from 'Test::call()': Return: 1
Test::func2 called from 'Test::call()': Return: 2
Test::func3 called from 'Test::call()': Return: 3

Live Demo on coliru.com

How to understand the pointer star * in C?

The rule of declaration in c is, you declare it the way you use it.

char *p means you need *p to get the char,

char **p means you need **p to get the char.

What are the pointer-to-member operators -* and .* in C++?

I hope this example will clear things for you

//we have a class
struct X
{
void f() {}
void g() {}
};

typedef void (X::*pointer)();
//ok, let's take a pointer and assign f to it.
pointer somePointer = &X::f;
//now I want to call somePointer. But for that, I need an object
X x;
//now I call the member function on x like this
(x.*somePointer)(); //will call x.f()
//now, suppose x is not an object but a pointer to object
X* px = new X;
//I want to call the memfun pointer on px. I use ->*
(px ->* somePointer)(); //will call px->f();

Now, you can't use x.somePointer(), or px->somePointer() because there is no such member in class X. For that the special member function pointer call syntax is used... just try a few examples yourself ,you'll get used to it

What exactly is the purpose of the (asterisk) in pointers?

* has different meaning depending on the context.

  1. Declaration of a pointer

    int* ap;  // It defines ap to be a pointer to an int.

    void foo(int* p); // Declares function foo.
    // foo expects a pointer to an int as an argument.
  2. Dereference a pointer in an expression.

    int i = 0;
    int* ap = &i; // ap points to i
    *ap = 10; // Indirectly sets the value of i to 10
  3. A multiplication operator.

    int i = 10*20; // Needs no explanation.

Pointers in C: when to use the ampersand and the asterisk?

You have pointers and values:

int* p; // variable p is pointer to integer type
int i; // integer value

You turn a pointer into a value with *:

int i2 = *p; // integer i2 is assigned with integer value that pointer p is pointing to

You turn a value into a pointer with &:

int* p2 = &i; // pointer p2 will point to the address of integer i

Edit:
In the case of arrays, they are treated very much like pointers. If you think of them as pointers, you'll be using * to get at the values inside of them as explained above, but there is also another, more common way using the [] operator:

int a[2];  // array of integers
int i = *a; // the value of the first element of a
int i2 = a[0]; // another way to get the first element

To get the second element:

int a[2]; // array
int i = *(a + 1); // the value of the second element
int i2 = a[1]; // the value of the second element

So the [] indexing operator is a special form of the * operator, and it works like this:

a[i] == *(a + i);  // these two statements are the same thing

In C, what does a variable declaration with two asterisks (**) mean?

It declares a pointer to a char pointer.

The usage of such a pointer would be to do such things like:

void setCharPointerToX(char ** character) {
*character = "x"; //using the dereference operator (*) to get the value that character points to (in this case a char pointer
}
char *y;
setCharPointerToX(&y); //using the address-of (&) operator here
printf("%s", y); //x

Here's another example:

char *original = "awesomeness";
char **pointer_to_original = &original;
(*pointer_to_original) = "is awesome";
printf("%s", original); //is awesome

Use of ** with arrays:

char** array = malloc(sizeof(*array) * 2); //2 elements

(*array) = "Hey"; //equivalent to array[0]
*(array + 1) = "There"; //array[1]

printf("%s", array[1]); //outputs There

The [] operator on arrays does essentially pointer arithmetic on the front pointer, so, the way array[1] would be evaluated is as follows:

array[1] == *(array + 1);

This is one of the reasons why array indices start from 0, because:

array[0] == *(array + 0) == *(array);

What does the * mean when in a C++ method signature?

It means that you're passing it a pointer to a character, which usually means that pointer points to the first character in an array of characters. With a pointer (*), you can do arithmetic, e.g. (fileName + 1) to get the second character. When you use a reference (&), you are implying that the receiving function should operate on the original data. Without the reference, the function is passed a copy, rather than the original.

Why is the asterisk before the variable name, rather than after the type?

They are EXACTLY equivalent.
However, in

int *myVariable, myVariable2;

It seems obvious that myVariable has type int*, while myVariable2 has type int.
In

int* myVariable, myVariable2;

it may seem obvious that both are of type int*, but that is not correct as myVariable2 has type int.

Therefore, the first programming style is more intuitive.

Why does the arrow (-) operator in C exist?

I'll interpret your question as two questions: 1) why -> even exists, and 2) why . does not automatically dereference the pointer. Answers to both questions have historical roots.

Why does -> even exist?

In one of the very first versions of C language (which I will refer as CRM for "C Reference Manual", which came with 6th Edition Unix in May 1975), operator -> had very exclusive meaning, not synonymous with * and . combination

The C language described by CRM was very different from the modern C in many respects. In CRM struct members implemented the global concept of byte offset, which could be added to any address value with no type restrictions. I.e. all names of all struct members had independent global meaning (and, therefore, had to be unique). For example you could declare

struct S {
int a;
int b;
};

and name a would stand for offset 0, while name b would stand for offset 2 (assuming int type of size 2 and no padding). The language required all members of all structs in the translation unit either have unique names or stand for the same offset value. E.g. in the same translation unit you could additionally declare

struct X {
int a;
int x;
};

and that would be OK, since the name a would consistently stand for offset 0. But this additional declaration

struct Y {
int b;
int a;
};

would be formally invalid, since it attempted to "redefine" a as offset 2 and b as offset 0.

And this is where the -> operator comes in. Since every struct member name had its own self-sufficient global meaning, the language supported expressions like these

int i = 5;
i->b = 42; /* Write 42 into `int` at address 7 */
100->a = 0; /* Write 0 into `int` at address 100 */

The first assignment was interpreted by the compiler as "take address 5, add offset 2 to it and assign 42 to the int value at the resultant address". I.e. the above would assign 42 to int value at address 7. Note that this use of -> did not care about the type of the expression on the left-hand side. The left hand side was interpreted as an rvalue numerical address (be it a pointer or an integer).

This sort of trickery was not possible with * and . combination. You could not do

(*i).b = 42;

since *i is already an invalid expression. The * operator, since it is separate from ., imposes more strict type requirements on its operand. To provide a capability to work around this limitation CRM introduced the -> operator, which is independent from the type of the left-hand operand.

As Keith noted in the comments, this difference between -> and *+. combination is what CRM is referring to as "relaxation of the requirement" in 7.1.8: Except for the relaxation of the requirement that E1 be of pointer type, the expression E1−>MOS is exactly equivalent to (*E1).MOS

Later, in K&R C many features originally described in CRM were significantly reworked. The idea of "struct member as global offset identifier" was completely removed. And the functionality of -> operator became fully identical to the functionality of * and . combination.

Why can't . dereference the pointer automatically?

Again, in CRM version of the language the left operand of the . operator was required to be an lvalue. That was the only requirement imposed on that operand (and that's what made it different from ->, as explained above). Note that CRM did not require the left operand of . to have a struct type. It just required it to be an lvalue, any lvalue. This means that in CRM version of C you could write code like this

struct S { int a, b; };
struct T { float x, y, z; };

struct T c;
c.b = 55;

In this case the compiler would write 55 into an int value positioned at byte-offset 2 in the continuous memory block known as c, even though type struct T had no field named b. The compiler would not care about the actual type of c at all. All it cared about is that c was an lvalue: some sort of writable memory block.

Now note that if you did this

S *s;
...
s.b = 42;

the code would be considered valid (since s is also an lvalue) and the compiler would simply attempt to write data into the pointer s itself, at byte-offset 2. Needless to say, things like this could easily result in memory overrun, but the language did not concern itself with such matters.

I.e. in that version of the language your proposed idea about overloading operator . for pointer types would not work: operator . already had very specific meaning when used with pointers (with lvalue pointers or with any lvalues at all). It was very weird functionality, no doubt. But it was there at the time.

Of course, this weird functionality is not a very strong reason against introducing overloaded . operator for pointers (as you suggested) in the reworked version of C - K&R C. But it hasn't been done. Maybe at that time there was some legacy code written in CRM version of C that had to be supported.

(The URL for the 1975 C Reference Manual may not be stable. Another copy, possibly with some subtle differences, is here.)

What is the function of an asterisk before a function name?

The asterisk belongs to the return type, and not to the function name, i.e.:

void* func_name(void *param) { . . . . . }

It means that the function returns a void pointer.



Related Topics



Leave a reply



Submit