I saw an online C++ test regarding the constructor. I can figure out most of the answers but am puzzled by some in the following. Hope someone can help me out.
Here's the example.
#include <iostream>
class A {
public:
A(int n = 0) : m_n(n) {
std::cout << 'd';
}
A(const A& a) : m_n(a.m_n) {
std::cout << 'c';
}
private:
int m_n;
};
void f(const A &a1, const A &a2 = A())
{
}
int main() {
A a(2), b;
const A c(a), &d = c, e = b;
b = d;
A *p = new A(c), *q = &a;
static_cast<void>(q);
delete p;
f(3);
std::cout << std::endl;
return 0;
}
What I don't really get is why "&d = c" doesn't output anything. Also adding another overloading constructor like A(const A *a) : m_n(a->m_n) { std::cout << 'b'; } doesn't output anything either for *q = &a. So what can I do to make it work?
Many thanks for any advice. I am very curious about this.
There's no output for these because d and q are not of type A, i.e. they are not A objects. d is a reference to A and q is a pointer to A. Initialising a reference and initialising or assigning a pointer does not manipulate the referred-to/pointed-to A object at all, hence no output.
To address your question - there is nothing to "make work," it works just as it should.
That to be more clear I will rewrite this statement
const A c(a), &d = c, e = b;
as
const A c(a);
const A &d = c;
Here d is declared as a reference to an object of type A. It does not create a new object. It refers to an object that is already created. In this case d referes to c. In fact d is simply an alias for object c.
This code snippet
A *p = new A(c), *q = &a;
also can be rewritten for simplicity
A *q = &a;
In this statement pointer q is simply assigned by the address of a. Neither object is created. Simply q now points to already created early object a.
&d = c doesn't output anything because you're not calling the constructor.
If we expand that code fragment a bit...
A &d = c
What your code is saying there is "declare d to be a reference to an object of type A, which points to c". Because you're creating a reference, you're not calling the constructor, c and d are the same object.
The same applies to q, but instead of creating a reference, you're creating a pointer and assigning it the address of an existing instance of type A. The constructor isn't called because you're not creating a separate object, you're linking to an existing one.
Related
When I searched for return *this, I found someone explaining it as a chained assignment function.
But when I follow the blogger's implementation, I found that this is not the case.
Though one has the code return *this, the other has not, the two results is same.
#include <iostream>
using namespace std;
class Wd {
private:
public:
int a;
int b;
Wd &operator=(Wd const &as) {
this->a = as.a;
this->b = as.b;
return *this;
};
};
int main() {
Wd a;
a.b =3;
a.a =4;
Wd c,b,d;
d.a=6;
d=c=b=a;
cout<<d.a<<a.a<<b.a<<c.a<<endl;
return 0;
}
Semantic of assignment expression like a=b is :
first, set the value of a to the value of b,
second, the value of the whole expression is the value of a after assignment. a=b=c is equivalent to a = (b=c).
As a=b is a.operator=(b), the return value of the operator must be the value of a after assignment, thus the following is the most common way of implementing it:
K &operator=(const K &arg) {
// code to assign this with values in arg
return *this; // return the current assigned object
}
So this
class Wd{
public:
int a;
int b;
Wd &operator =(Wd const &as){
this->a = as.a;
this->b = as.b;
return *this;
};
};
creates an object with only one function operator=.
That function is defined as returning a reference to the invoking object.
return *this;
says 'return what the this object points at'. this points at the current Wd instance. If the retrun type we Wd then it would retunr a copy, but becuase the return type is Wd& it returns a reference to it, this is effectively a pointer
so now look at the main code
Wd a;
a.b =3;
a.a =4;
first we create a Wd and initialize its members.
Then we do (simplified a bit)
Wd c;
Wd d;
d = c = a;
d = c= a translates to
d.operator=(c.operator=(a))
and because c.operator=(a) returns a reference to a this is equivalent to
d.operator=(a)
One of the main reason for the existance of references is to permit chaining like this. The most well known one is this
cout << x << " " << y << "!!" << z;
this works because operator<< for streams is defined as returning a reference to its invoking stream.
I'm trying to understand below code from the beginner's book. (edit: 'programming principles and practice using c++' page 1085) I don't quite get why temporary strings are made according to the comments.
const char* string_tbl[ ] = { "Mozart", "Grieg", "Haydn", "Chopin" };
const char* f(int i) { return string_tbl[i]; }
void g(string s){}
void h()
{
const string& r = f(0); // bind temporary string to r
g(f(1)); // make a temporary string and pass it
string s = f(2); // initialize s from temporary string
cout << "f(3): " << f(3) // make a temporary string and pass it
<<" s: " << s
<< " r: " << r << '\n';
}
f() returns a pointer to const char, right?
Shouldn't const string& r = f(0); assign a 'pointer to char' (in this case of the string literal in the global array) to the reference variable so that the original can be accessed (read-only) with r[] etc?
and g(f(1)); pass a pointer to g() where the string s is then initialized with the pointer?
What am I missing? Do const char* always produce a temporary string when it's returned from a function?
There is a implicit conversion, the code
string s = f(2);
is equal to
string s = string(f(2));
I don't quite get why temporary strings are made according to the comments.
The whole matter is that a char const* and a std::string are totally different data types.
For comparison:
class A { };
class B { };
void f(A a);
void g()
{
B b;
f(b); // does not work...
}
I'm pretty sure you have encountered that already.
Now let's change class A:
class A
{
public:
A() { } // default constructor
A(B b) { } // accepting an instance of B
};
Now, you can do:
B b;
f(A(b)); // create a TEMPORARY A from B; you need it, as f ONLY accepts an A!
f(b); // again, create a temporary just as before - this time IMPLICITLY
You can disallow implicitly creating A from B by making the constructor explicit:
class A
{
public:
A() { }
explicit A(B b) { } // now A cannot be created implicitly any more
};
B b;
//f(b); // now is not accepted by compiler any more
f(A(b)); // this still works, of course
Exactly the same with std::string: It has a non-explicit constructor accepting char const*...
int main()
{
int a = 10;
const int &b = a;
int &c = b; //gives error : C should a reference to a const b
auto d = b; // why const is ignored here?
d = 15;
cout << a << d;
}
In c++ Primer, it's mentioned that "const in reference type is always low-level " Then how come auto d = b is not constant?
Because the type deduction rules for auto deduce to an object type. You are copy initializing a new int from the one referenced by b.
That's by design. We want to create new objects without explicitly specifying their type. And more often than not, it's a new object that is a copy some other object. Had it deduced to a reference, it would defeat the intended purpose.
If you want the deduced type to be a reference when the initializer is a reference, then that is accomplished with a placeholder of decltype(auto):
decltype(auto) d = b; // d and b now refer to the same object
d = 15; // And this will error because the cv-qualifiers are the same as b's
For auto d = b, you're declaring d as non-reference. That means d will be a new object copied from b, then the reference part of b will be ignored, after that, the const-ness is ignored too. So the type of d is int.
You can declare d as reference explicitly, then the const-ness of b won't be ignored. e.g.
auto& d = b; // the type of d is const int &
Because the deducted type is as an int, not an int&.
That means d is not a reference.
I have a function getA() which returns a const reference of base type A, since it's const, it cannot dynamic_cast it, so I make a copy of the const reference and then created a reference to the copied object, but when I call dynamic_cast to the reference of the copied object, it fails, the code is shown below:
struct A {
int c = -1;
virtual ~A() {}
};
struct B : A {int aa = 0;};
const A& getA(){
std::unique_ptr<A> ap(new B);
return *ap;
}
int main()
{
const A& a = getA();
A acopy = a;
acopy.c = -2;
A& acopyr = acopy;
std::cout << a.c << std::endl;
try{
B& b = dynamic_cast<B&>(acopyr);
std::cout << b.aa << std::endl;
}catch(std::bad_cast b){
std::cout << "bad" << std::endl;
}
}
The output is
-1
bad
acopy is an object of dynamic (and static) type A. Notice how it was declared: an object of type A. So of course it cannot be cast to a B&.
From your description, I take it you just want to dynamically cast getA() to a const reference to B. There's nothing stopping you from that:
const B& b = dynamic_cast<const B&>(getA());
Side note: I assume the getA implementation in your question is just for demonstration purposes, but it's very wrong. As soon as ap goes out of scope (that is, as soon as getA returns), it will destroy the object to which it points, so you're returning a dangling reference and thus invoking Undefined Behaviour.
I have to write definition of the code below. I undarstand some basics of OOP Cpp, I know what is *x or &x, but that's not enough... The main fact is that i cant understand line B* p = new D, m, *k; i cant understand what m and *k stand for.
class B {
public:
virtual void msg() { cout << "classB"; }
};
class D: public B {
public:
virtual void msg() { cout << "classD"; }
};
int main() {
B* p = new D, m, *k;
p->msg(); k = &m; k->msg();
. . .
}
Help, if you can explain how (and why so) this code will work.
thanks, for your time.
It declares multiple variables at once. This is basically the same as:
B *p = new D;
B m;
B *k;
So p is a pointer to an instance of D allocated with new. m is a local instance of class B and k is a pointer to B that is later assigned to point at m.
The msg function is called on both allocated objects via the pointers p and k.
Note that * applies to each variable declaration separately. So B* a, b; doesn't declare two pointers, but instead declares one pointer and one local object. This is the reason, that many people prefer to write the * directly in front of the variable name: B *a, b makes this a bit more obvious.
In C++ you can declare more then one variable in one statement. Therefore B* p = new D, m, *k; declares the variables p, m and k. The * for pointer declarations binds to the variable name, therefore it's basically identical to
B* p = new D;
B m;
B* k;
Nothing fancy, it's just plain old C.
B* p = new D, m, *k;
is just shortcut for:
B* p = new D;
B m;
B* k;
p is a pointer to an object of the class B (or D, because it is a child of the class B). p->msg(); is similar to (*p).msg();. m is an object of the class B, so we can get pointer to it by & operator and store it in k (which is a pointer to an object of the class B).
And
B* p = new D, m, *k;
is just
B* p = new D;
B m;
B* k;
Notice: you should put * if it is needed each time