Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
I have some questions about C++ from a C# developer.
For a few days I have been looking at some C++ code, and I have the following questions:
When do use Foo::, Foo. and Foo-> ?
When do I use a real constructor and when just String a; (sometimes I need to do something like String a("foo");)
What is the difference between these signatures: int foo(int a) and int foo(int &a)?
:: is used either to explicitly specify a namespace (std::string, for example, for the string class in the namespace std), or for static members of a class.
. is used much as in C#, to refer to a member of a class.
-> is used with pointers. If p is a pointer to an object obj, then p->x has the same meaning as obj.x.
when do i use a real constructor and when just String a; (sometimes i need to do something like String a("foo");)
When you need to. String a is roughly equivalent to C#'s a = new String() (with the caveat that if String is a non-POD type, it may contain uninitialized members.)
If you need a initialized to a specific value, you do that. (either with String a("foo"), or with String a = "foo")
where is the difference between these signatures: int foo(int a) and int foo(int &a)?
The & denotes a reference. It's not quite a C# reference, but there are similarities. In C#, you have value types and reference types, and reference types are always passed by reference.
In C++, there's no such distinction. Every type can be passed by value or by reference. The type T& is a reference to T. In other words, given the following code:
void foo(int& j);
void bar(int j);
int i = 42;
foo(i);
bar(i);
foo will get a reference to i, which means it it can modify the value of i.
bar will get a copy of i, which means that any modifications it makes will not be reflected in i.
You often use const T& (a reference to const T) as a way to avoid the copy, while still preventing the callee from modifying the object.
1: Assuming you which to call a method
Foo::theMethod(...)
is for example used when calling a static method of a class Foo
Foo.theMethod(...)
is when you have an object named Foo
Foo->theMethod(...)
is when you have a pointer to a object of named Foo
2:
String a;
calls the default constructor that takes no arguments
String a("foo")
calls a overloaded constructor
3:
int foo(int &a)
takes a reference to an integer, so within the method you are able to manipulate a.
int foo(int a)
makes a copy, manipulating it wont have any effect of the actual parameter passed in after leaving the method.
Question 1:
It depends on what Foo is. The :: operator is called the scope
resolution operator; the operand on the right must be a namespace or a
class, and the operand to the left a member of the namespace or class.
If Foo is a class, Foo:: can be used to access a static member, or
from within a member of a derived class, to access the member of the
base class: e.g.:
class Foo
{
public:
virtual void f();
static void g();
};
int h()
{
Foo::g();
}
class Derived : public Foo
{
public:
virtual void f()
{
Foo::f(); // Call function in base class...
}
}
It's often used to access namespace members as well, e.g. std::cout
(the cout object in namespace std).
The . operator is a member access operator, and requires an object (or
a reference to an object) as the left hand operand. Thus (using the
above definitions):
Foo obj;
obj.f();
void i( Foo& rFoo )
{
rFoo.f();
}
It can also be used to access static members, if you have an instance:
Foo obj;
obj.g();
The -> is very much like the . operator, except that it takes a
pointer to an instance, rather than an instance, and (very importantly)
it can be overloaded. Thus:
Foo* obj;
obj->g();
// And if Ptr is a user defined type with an overloaded
// `operator->` which returns a Foo*
Ptr obj;
obj->g();
Again, you can also use this syntax to access a static member, if you
have a pointer to an object.
Question 2:
The definition String a; calls a real constructor. You use String
a; when you want the default constructor; the one with no parameters.
You use String a( "foo" ); when you want the constructor which takes a
char const* (or a char const (&)[4], but that's highly unlikely, since it
will only work for a string literal with exactly three characters).
In general, when defining variables:
String a; // default constructor...
String a1(); // NOT what it looks like: this is a
// function declaration, and not the
// definition of a variable!!!
String b( x, y, z ); // constructor taking x, y and z as arguments...
String c = x; // implicitly convert `x` to String, then
// copy constructor.
The last form is a bit tricky, since the copy constructor may be (and
almost always is) elided, but the legality of the program is defined by
the rule above: there must be a way of implicitly converting x into a
String, and String must have an accessible copy constructor.
In other contexts, e.g. new String(), the form with empty parameters
can be used for "value construction", which is the default constructor
if there is a user defined one, otherwise zero initialization.
Question 3:
The first is pass by value, and passes a copy of the argument to the
function. The second is pass by reference, and passes a reference
(which behaves sort of like a hidden, automatically dereferenced
pointer) to the function. Thus:
void f( int a )
{
++ a; // Modifies local copy, has no effect on the argument.
}
void g( int& a )
{
++ a; // Modifies the variable passed as an argument.
}
Note that in the first case, you can pass an arbitrary expression; in
the second, you must pass something called an lvalue—that is,
something you can access afterwards using a similar expression (a named
variable, or a dererenced pointer, or an element in a named array,
etc.).
String a : construct an empty String object
String a("foo") : construct a String object initalized to "foo"
int foo(int a) : pass a by value/copy to foo. Inside foo if you modify a , a will not be impacted outside foo
int foo(int& a) : pass a by reference inside foo. If you modify a , a will also be modify once foo ended
Foo:: - Static methods
Foo. - Instance Methods when you have a stack object instance. (MyObject obj)
Foo-> - Instance methods when you have a object pointer. (MyObject* pObj = new MyObject())
Whenever you need to pass some value to the constructor.
int& is a reference to an int. Any changes to a within the method will affect a outside the method. (Equivalent to ref in C#)
Related
Inside setMyInt function I have used two statements to set myInt variable. Though both of them gives me the same result. Is there any conceptual difference in working of them?
#include <iostream>
using namespace std;
class Bar{
int myInt;
public:
const int getMyInt() const {
return myInt;
}
void setMyInt(int myInt) {
Bar::myInt = myInt;
this->myInt=myInt;
}
};
int main(){
Bar obj;
obj.setMyInt(5);
cout<<obj.getMyInt();
return 0;
}
You can't really compare them, and they are not interchangeable, but because in C++ you can leave certain things out in certain cases, here it looks like they are.
In fact, both lines are short for:
this->Bar::myInt = myInt;
This means, set the value of the object Bar::myInt (the member called myInt in the scope of the class Bar), which is encapsulated by the object pointed to by this, to the value of the (other) variable myInt.
You can leave out Bar:: because this is a Bar* so that's implicit; you can leave out this-> because you're in a member function so that's implicit too.
More generally, -> performs a pointer dereference and object access, whereas :: is the "scope resolution operator" which fully qualifies a name.
“->” is used as a pointer
“.” Is used for object members variables/ methods
“::” Is used for static variables/ methods or for objects from another scope.
I am faced with a very puzzling issue. I am trying to construct an object using a variable as a parameter.
Have a look at this code please:
#include <iostream>
class A {
public:
A() : val(0) {};
A(int v) : val(v) {};
private:
int val;
};
main() {
int number;
A a; /* GOOD, object of type A, created without arguments */
A b(2); /* GOOD, object of type A, created with one argument */
A c(); /* BAD, C++ thinks this is declaration of
a function returning class A as a type */
A(d); /* GOOD, object of type A again; no arguments */
A(number); /* BAD, tries to re-declare "number" as object of type A */
}
I think I do understand why objects "a", "b" and "d" can be created, whereas the rest can not.
But I would really need the syntax of the last declaration, i.e.
A(number);
to create a temporary object, to pass as an argument to another object.
Any idea how to work around it?
Kind regards
Your intention is to create a temporary object, but this object would also be anonymous : you have no way to refer to it after the semicolon.
There is no point in creating an anonymous temporary object just to discard it. You have to instantiate your temporary directly at the call site of the ctor/method that will consume it.
Solution
To pass an anonymous temporary object to a function, you actually need to instantiate it inside the arguments' list :
functionExpectingA(A(number));
For the line of "c declaration", you are poking at the most vexing parse. If you actually need to pass a default constructed A object as an argument to another object constructor, you need to add another pair of braces to do the trick (so the compiler can distinguish it from a function declaration) :
class OtherClass
{
public:
OtherClass(A a)
{
//...
};
};
OtherClass obj((A()));
^ ^
EDIT #1 : jrok pointed out that the argument given to A constructor is not enough to resolve the ambiguity.
If you need to pass an anonymous temporary object that is built with an argument, there is no ambiguity (so no need for the extra parentheses), you still need the parentheses around the anonymous object construction.:
OtherClass obj((A(number)));
C heritage : a single argument is not enough
EDIT #2 : "why giving a single argument to A constructor does not resolve the ambiguity".
What happens with OtherClass obj(A(number)); ?
This is a declaration for a function named obj, taking an A object as its unique argument. This argument is named number.
i.e: It is exactly equivalent to OtherClass obj(A number);. Of course, you can omit the argument name at function declaration. So it is also sementically equivalent to OtherClass obj(A);
The syntax with parentheses around the object name is inherited from C :
int(a); // declares (and defines) a as an int.
int a; // strictly equivalent.
What with more arguments to the constructor then ?
If you added a ctor to OtherClass taking two (or more) arguments :
OtherClass(A a1, A a2)
{
//...
};
Then this syntax :
A arg1, arg2;
OtherClass obj(A(arg1, arg2));
Would this time actually declare obj as an instance of OtherClass.
This is because A(arg1, arg2) cannot be interpreted as name declaration for an A. So it is actually parsed as the construction of an anonymous A object, using the constructor with 2 parameters.
I'm sorry if this question gets reported but I can't seem to easily find a solution online. If I override operator()() what behavior does this define?
The operator() is the function call operator, i.e., you can use an object of the corresponding type as a function object. The second set of parenthesis contains the list of arguments (as usual) which is empty. For example:
struct foo {
int operator()() { return 17; };
};
int main() {
foo f;
return f(); // use object like a function
}
The above example just shows how the operator is declared and called. A realistic use would probably access member variables in the operator. Function object are used in many places in the standard C++ library as customization points. The advantage of using an object rather than a function pointer is that the function object can have data attached to it.
suppose we have a class
class Foo {
private:
int PARTS;
public:
Foo( Graph & );
int howBig();
}
int Foo::howBig() { return this->PARTS; }
int Foo::howBig() { return PARTS; }
Foo::Foo( Graph &G ) {
<Do something with G.*>
}
Which one of howBig()-variants is correct?
The &-sign ensures that only the reference for Graph object
is passed to initialization function?
In C I would simply do something like some_function( Graph *G ),
but in C++ we have both & and *-type variables, never understood
the difference...
Thank you.
When you've local variable inside a member function, then you must have to use this as:
Foo::MemberFunction(int a)
{
int b = a; //b is initialized with the parameter (which is a local variable)
int c = this->a; //c is initialized with member data a
this->a = a; //update the member data with the parameter
}
But when you don't have such cases, then this is implicit; you need to explicity write it, which means in your code, both versions of howBig is correct.
However, in member initialization list, the rules are different. For example:
struct A
{
int a;
A(int a) : a(a) {}
};
In this code, a(a) means, the member data a is being initialized with the parameter a. You don't have to write this->a(a). Just a(a) is enough. Understand this visually:
A(int a) : a ( a ) {}
// ^ ^
// | this is the parameter
// this is the member data
You can use this-> to resolve the dependent name issue without explicitly having to spell out the name of the base. If the name of the base is big this could arguably improve readability.
This issue only occurs when writing templates and using this-> is only appropriate if they're member functions, e.g.:
template <typename T>
struct bar {
void func();
};
template <typename T>
struct foo : public bar {
void derived()
{
func(); // error
this->func(); // fine
bar<T>::func(); // also fine, but potentially a lot more verbose
}
};
Which one of howBig()-variants is correct?
both in your case, the compiler will produce the same code
The &-sign ensures that only the reference for Graph object is passed to initialization function? In C I would simply do something like some_function( Graph *G ), but in C++ we have both & and *-type variables, never understood the difference...
there is no difference as per the use of the variable inside the method(except syntax) - in the case of reference(&) imagine as if you've been passed an invisible pointer that you can use without dereferencing
it(the &) might be "easier" for clients to use
Both forms of Foo::howBig() are correct. I tend to use the second in general, but there are situations that involve templates where the first is required.
The main difference between references and pointers is the lack of "null references". You can use reference arguments when you don't want to copy the whole object but you want to force the caller to pass one.
Both are correct. Usually shorter code is easier to read, so only use this-> if you need it to disambiguate (see the other answers) or if you would otherwise have trouble understanding where the symbol comes from.
References can't be rebound and can't be (easily) bound to NULL, so:
Prefer references to pointers where you can use them. Since they cannot be null and they cannot be deleted, you have fewer things to worry about when using code that uses references.
Use const references instead of values to pass objects that are large (more than say 16 or 20 bytes) or have complex copy constructors to save copy overhead while treating it as if it was pass by value.
Try to avoid return arguments altogether, whether by pointer or reference. Return complex object or std::pair or boost::tuple or std::tuple (C++11 or TR1 only) instead. It's more readable.
I want to know what's difference in the following two class.
example 1:
class A
{
string name;
public:
A(const char* _name):name(_name){}
void print(){cout<<"A's name:"<<name<<endl;}
};
example 2:
class A
{
string name;
public:
A(const char* _name){name(_name);}
void print(){cout<<"A's name:"<<name<<endl;}}
why the example 1 is passed and the last one is wrong?
Thanks
In example 1 you initialize the string with the given value right away.
In example 2 you create an empty string first and assign it later on.
Despite some performance differences and ignoring possible differences due to copy constructor handling etc. it's essentially the same result.
However once you use a const member you'll have to use example 1's way to do it, e.g. I usually create unique IDs the following way:
class SomeObject
{
static unsigned int nextID = 0;
const unsigned int ID;
SomeObject() : ID(nextID++)
{
// you can't change ID here anymore due to it being const
}
}
The first example is an actual initialization. It has a number of advantages, including being the only way to set up const members, and having proper exception-safety.
The second example is not valid C++, AFAIK. If you had instead written name = name_, then this would just be normal assignment. Of course, this isn't always possible; the object might be const, or not have an assignment operator defined. This approach could also be less efficient that the first example, because the object is both default-initialized and assigned.
As for why the initializer list is before the constructor body; well, that's just the way the language has been defined.
That's just how the language is defined. The member initializers should be placed before the body of the constructor.
In the first example the member name is initialized with a ctr getting char * as parameter.
In the second case it is initialized with a default ctr at first and it gets value by the assignment operator (operator=) later. That's why it is wrong with your case that it is already constructed there so you can not use the ctr once again you could just use the assignment operator.
The reason is that name lookup works different in initializer lists and function bodies:
class A
{
std::string foo; // member name
public:
A(const char* foo) // argument name
: foo(foo) // member foo, followed by argument foo.
{
std::cout << foo; // argument foo.
}
};
If the initializer list was inside the function body, there would be an ambiguity between member foo and argument foo.
The motivation behind the initialization list is due to const field holding a object by value (as opposed to reference/pointer field).
Such fields must be initialized exactly once (due to their const-ness). If C++ didn't have initialization list then a ctor would look something like:
class A {
public:
const string s;
const string t;
A() {
// Access to either s or t is not allowed - they weren't initialized
s = "some-string";
// now you can access s but you can't access t
f(*this);
t = "some other string";
// From now you can access both ...
}
}
void f(A& a) {
// Can you access a.s or a.t?
cout << a.s << a.t;
}
Without an initialization list a ctor can pass a partially-initialized object of type A to a function, and that function will have no way of knowing which fields are initialized yet. Too risky and very difficult for the compiler/linker to check.