dynamic_cast<> question using Stroustrup example - c++

I'm testing a dynamic_cast<> example in Stroustrup C++ 4th Ed Page 642 and it does not compile. I'm using the following picture directly from the book trying to learn how it works. Does anyone know if this is Eratta (its not in his published errata doc) or I have misread something?
Stroustrup Graphic, dashed line represents protected:
#include <iostream>
using namespace std;
// H = Ival_box
class H {
};
// G = Ival_slider
class G : public H {
};
// I = BBwindow
class I {
};
// F = BB_slider
class F : public I {
};
// X = BB_ival_slider
class X : public G, protected F {
};
int main(int argc, char *argv[])
{
// works
X xx{};
if (auto p = dynamic_cast<G*>(&xx))
cout << "X*...G*" << endl;
// works
G gg{};
if (auto p = dynamic_cast<H*>(&gg))
cout << "G*...H*" << endl;
// compilation error, 'I' is not polymorphic
I ii{};
if (auto p = dynamic_cast<H*>(&ii))
cout << "I*...H*" << endl;
return 0;
}
Compilation and results:
clang++ -std=c++11 -pedantic -Wall test164.cc && ./a.out
test164.cc:31:18: error: 'I' is not polymorphic
if (auto p = dynamic_cast<H*>(&ii))
^ ~~~
1 error generated.
Compilation and results with error commented out:
clang++ -std=c++11 -pedantic -Wall test164.cc && ./a.out
X*...G*
G*...H*

The error explains what is wrong. Dynamic cast is only allowed for polymorphic types (except when casting upwards in inheritance hierarchy).
A class is polymorphic only if it has at least one virtual function. I does not have any virtual functions. Therefore it is not polymorphic. You must add a virtual function to I in order for this to work.
Note that even then, dynamic_cast<H*>(&ii) can never be a non-null pointer (i.e. true) because ii is not a base sub object of an object of type H.

Related

Random number example from Stroustrup has compilation error

I'm using this random number example from Stroustrup C++ 4th Ed Page 1182. The compiler is reporting an error on the line with auto, stating that auto cannot be used with non-static members of classes. I'm confused on what the type of this bind results in. Does anyone know how to resolve the error so the random number generator can be used?
#include <random>
using namespace std;
class Rand_int {
public: // added
Rand_int(int lo, int hi) : p{lo,hi} { }
int operator()() const { return r(); }
private:
uniform_int_distribution<>::param_type p;
auto r = bind(uniform_int_distribution<>{p},default_random_engine{});
};
int main()
{
Rand_int ri {0,10};
int pz = ri();
return 0;
}
Compilation error:
clang++ -Wall -std=c++11 -pedantic test252.cc && ./a.out
test252.cc:11:5: error: 'auto' not allowed in non-static class member
auto r = bind(uniform_int_distribution<>{p},default_random_e...
^~~~
You can't use auto for the type of a non-static member of a class, so the code example is wrong.
Instead, you can do:
class Rand_int {
private:
std::function<int()> r = bind(uniform_int_distribution<>{p},default_random_engine{});
// ...
};
This converts the return type of std::bind to a void function returning an int, which is the desired behavior.
Here's a demo.

Undefined reference for unoptimised constexpr used as default parameter

I do not understand why the below code compiles with GCC optimised, but fails to link with "undefined reference to `base::A_VAL'" when unoptimised. Am I doing something dodgy? Is this something that's a compiler bug (never is)? This is with g++ 5.4.0 on Ubuntu.
base.h:
class base {
public:
static constexpr unsigned int A_VAL{0x69U};
};
derived.h:
#include "base.h"
#include <iostream>
using namespace std;
class derived : public base
{
public:
int some_func(void) {
cout << "Some func" << endl;
return 0;
}
};
concrete.h:
#include "derived.h"
#include <utility>
class concrete : public derived
{
public:
concrete(int a, std::pair<unsigned int, unsigned int> data = {A_VAL, A_VAL}) {
some_func();
std::cout << "First: " << data.first << " Second: " << data.second << endl;
}
};
test.cpp:
#include "concrete.h"
int main (int argc, char *argv[])
{
concrete c{1};
c.some_func();
}
g++ -O2 -std=c++14 -o test test.cpp
Fine.
g++ -O0 -std=c++14 -o test test.cpp
/tmp/ccm9NjMC.o: In function `main':
test.cpp:(.text+0x23): undefined reference to `base::A_VAL'
test.cpp:(.text+0x28): undefined reference to `base::A_VAL'
collect2: error: ld returned 1 exit status
When optimizing GCC is probably able to determine (after inlining an constant folding) that the body of concrete's constructor can be replaced pretty much by
some_func();
std::cout << "First: " << A_VAL << " Second: " << A_VAL << endl;
Since operator<< for the standard stream class takes integers by value, and A_VAL is a constant expression, the call above doesn't require there to be any storage for A_VAL. Its value is just plugged in. As such, GCC doesn't need there to be an out of class definition for A_VAL, as is normally required for static class members.
When not optimizing, GCC quite likely initializes the pair object. std::pair's constructor takes objects by reference, and a reference requires an object to bind to. So the the definition of A_VAL becomes required and so the linker complains.
You need to define the object somewhere (pre C++17)
// At namespace scope
constexpr unsigned base::A_VAL;
Or switch to compiling as C++17. Then A_VAL (like all constexpr static members data) will be implicitly an inline variable, and the compiler will resolve its definition by itself.
I'm not sure howconstexpr affecting this, but you just declared static class variable, but not defined it. I.e. usually you need to have constexpr unsigned int base::A_VAL{0x69U}; somewhere in .cpp file.

Incorrect use of explicit keyword in c++

I wanted to create a class MPSList where constructor has an explicit keyword associated with it.
Following is the bare minimal code:
class MPSList {
public:
explicit MPSList(int n) : n_(n) {
mpsL.resize(n_, std::vector<MPSNode>{});
std::cout << mpsL.size() << std::endl;
}
private:
struct MPSNode {
double s_;
};
std::vector<std::vector<MPSNode>> mpsL;
int n_ = -1;
};
CPP file that creates the object of MPSList class.
#include <iostream>
#include "MPSList.hpp"
int main() {
double n = 10.9;
MPSList mps(n);
}
On compiling the above CPP file, I had expected to see an error in initializing the object. As I am passing a double whereas the constructor is explicitly expecting an int.
Command to compile:
g++ -std=c++14 -I../include test.cpp
./a.out
Explicit stops the compiler from doing something like this:
void fn(MPSNode x); // or void fn(const MPSNode& x)
fn(3.0);
The above snippet would compile if you didn't use explicit, and the line that calls fn is equivalent to:
fn(MPSNode(3.0));
This is an implicit conversion from double to MPSNode. Narrowing conversions have relatively little to do with it.
However, you will find that the following will not compile:
MPSList mps{n};
Use uniform initialisation syntax if you want to catch problems like that.

Should exceptions thrown from class member initializers call std::terminate()?

Given this code:
struct A {
A(int e) { throw e; }
};
struct B {
A a{42}; // Same with = 42; syntax
};
int main() {
try {
B b;
} catch (int const e) {
return e;
}
}
When compiled with GCC (versions 4.7.4, 4.8.5, 4.9.3, 5.4.0, 6.3.0):
$ g++ -std=c++11 test.cpp -o test; ./test ; echo $?
terminate called after throwing an instance of 'int'
Aborted
134
But when compiled with Clang (version 4.0.0):
$ clang++ -std=c++11 test.cpp -o test; ./test ; echo $?
42
Which behavior is correct?
This is a bug in GCC (Bug 80683).
If the constructor is the first op in the try/catch clause, then the compiler considered it as being outside of it although it should include it.
For example, the following works just fine:
#include <iostream>
struct A {
A(int e) { throw e; }
};
struct B {
A a{42}; // Same with = 42; syntax
};
int main() {
try {
// The following forces the compiler to put B's contructor inside the try/catch.
std::cout << "Welcome" << std::endl;
B b;
} catch (int e) {
std::cout << "ERROR: " << e << std::endl; // This is just for debugging
}
return 0;
}
Running:
g++ -std=c++11 test.cpp -DNDEBUG -o test; ./test ; echo $?
Outputs:
Welcome
ERROR: 42
0
My guess is that is that due to compiler optimization, it moves the constructor to the beginning of the main function. It assumes that the struct B has no constructor, then it assumes that it would never throw an exception, thus it is safe to move it outside of the try/catch clause.
If we will change the declaration of struct B to explicitly use struct A constructor:
struct B {
B():a(42) {}
A a;
};
Then the result will be as expected and we will enter the try/catch, even when removing the "Welcome" printout:
ERROR: 42
0
Clang is correct. References about that can be found in C++ standard reference draft n4296 (emphasize mine):
15.3 Handling an exception [except.handle]
...3 A handler is a match for an exception object of type E if
(3.1) — The handler is of type cv T or cv T& and E and T are the same type (ignoring the top-level cv-qualifiers),
Here an int is thrown, and the handler declares a const int. There is a match and the handler shall be invoked.

Template object as class parameter gives error before compiling

Here is the code:
#include <iostream>
using namespace std;
template<class OwnerType>
class Move {
public:
Move() {}
Move(OwnerType &_owner) {
owner = &_owner;
}
void GetPosition() {
cout << owner->x << endl;
}
OwnerType *owner;
};
class Entity {
public:
int x = 50;
Move<Entity> *move;
};
int main() {
Entity en;
en.x = 77;
en.move = new Move<Entity>(en); // sign '=' is underlined by VS
en.move->GetPosition();
return 0;
}
Error it gives :
a value of type "Move<Entity> *" cannot be assigned to an entity of type "Move<Entity> *"
The program is compiling, working as expected and gives expected values, however error is still here.
It's probably something to do with templates and compiling time and stuff but I don't have enough knowledge to know what this error actually represents.
Also don't worry about leaks since this was just me testing, error is what I don't understand.
Thanks in advance.
Intellisense is known for displaying invalid errors (see for example Visual Studio 2015: Intellisense errors but solution compiles), trust the compiler and linker, as suggested in comments.
However, this error is quite annoying, try closing the solution, delete the .suo file (it's hidden), and open in again. More info on what a .suo file is given here Solution User Options (.Suo) File
Side note, in your code example main is missing ().
so it is not Error.
it is Intellisense :
see:
Error 'a value of type "X *" cannot be assigned to an entity of type "X *"' when using typedef struct
Visual Studio 2015: Intellisense errors but solution compiles
old:
your main needs ():
this works for me:
#include<iostream>
using namespace std;
template<class T> class Move {
public:
Move() {}
Move(T &_owner) {
owner = &_owner;
}
void GetPosition() {
cout << owner->x << endl;
}
T *owner;
};
class Entity {
public:
int x = 50;
Move<Entity> *move;
};
int main(){
Entity en;
en.x = 77;
en.move = new Move<Entity>(en); // sign '=' is underlined by VS
en.move->GetPosition();
return 0;
}
output:
77