C++ - Confusion over particular example of class instantiation from Professor - c++

My professor gave the following code:
Main.cpp
#include "state.h"
#include <string>
#include <iostream>
using namespace std;
int main(int argc, char const *argv[]){
const int success = 0;
string name;
State x;
State y = "s2"; // This doesn't compile
State z = y;
State* p = new State(z);
x = *p;
p->set_name("s3");
delete p;
x.get_name(name);
std::cout << "Name of state x is " << name << std::endl;
std::cout << "Total number of states is " << State::total_number_of_states() << std::endl;
return success;
}
State.h
#ifndef STATE_H
#define STATE_H
#include <string>
using namespace std;
class State
{
private:
string* name; // str pointer used for illustrative purposes
static int number_of_states;
public:
State();
State(string state_name);
State(const State& state); // Will basically be the copy constructor
virtual ~State();
State& operator=(const State& state); // Copy on equal
void get_name(string& state_name) const;
void set_name(string state_name);
static int total_number_of_states();
};
typedef State *State_pointer;
#endif
In g++ 4.8 on Ubuntu, I get the following error:
$ g++ example_main_1.cpp state.cpp
example_main_1.cpp: In function ‘int main(int, const char**)’:
example_main_1.cpp:14:12: error: conversion from ‘const char [3]’ to non-scalar type ‘State’ requested
State y = "s2"; // This doesn't compile
I asked him about this in class, he said that this is valid C++ and that it should work. I've never seen this kind of class instantiation before, where it would have to convert from a string literal to a std::string then convert that to a State object.
My professor then went on to point out that there are other equivalent invocations that are extremely close:
State y = "s2"; // Does NOT compile
State y("s2"); // Does compile
State y = string("s2"); // Does compile
What's going on here? Why does the first not compile, but the second and third do? As well, is my professor mistaken in saying that the first statement should work? Or is it behavior that's compiler specific?

It looks like your State object has a constructor that takes string. The literal "s2" is type const char [3]. This is why you are receiving the error.
It is also compiler specific. The following code snippet works in VS2013, yet not G++:
struct State
{
State(string s) { }
};
int main() {
State s = "a";
}

Related

Struggling with pointers to functions and references

I am working through this problem I found on Git to brush up on some skills. Using friend is prohibited. C++ styling should be used compared to C.
Essentially, I cannot call the identify() function that belongs to the Brain member variable in my Human class. It just will not let me access it. If you can code this up, and explain where I am going wrong, that would be great.
Create a Brain class, with whatever you think befits a brain. It will have an Identify() function that returns a string containing the brain's address in memory, in hex format, prefixed by 0x.
Then, make a Human class, that has a constant Brain attribute with the same lifetime. It has an identify() function, that just calls the identity() function of its Brain and returns its result.
Now, make it so this code compiles and displays two identical addresses:
int main(){
Human bob;
std::cout << bob.identify() << "\n";
std::cout << bob.getBrain().identify() << "\n";
}
Here is what I have so far:
#pragma once
#include "Brain.h"
class Human
{
const Brain humanBrain;
public:
Human();
std::string identify();
};
#include "Human.h"
#include <iostream>
#include <string>
#include <sstream>
Human::Human()
{
this->humanBrain = new Brain;
}
std::string Human::identify()
{
Brain b = this->humanBrain.identify(); // This is essentially what I am trying to call--and I can't access it.
const Brain * ptr = humanBrain;
std::ostringstream test;
test << ptr;
return test.str();
}
#pragma once
#include <string>
#include <iostream>
class Brain
{
int age;
std::string gender;
void* ptr;
public:
Brain();
//std::string getBrain();
const std::string identify();
void setPtr(void* p);
};
#include "Brain.h"
#include <iostream>
#include <sstream>
Brain::Brain()
{
age = 10;
gender = "male";
}
const std::string Brain::identify()
{
//const Brain* bPtr = &this;
const Brain* bPtr = this;
ptr = this;
std::ostringstream test;
test << &bPtr;
std::string output = "Brain Identify: 0x" + test.str();
return output;
}
Your Human::humanBrain member is declared as type const Brain, which is correct per the instructions, however your Brain::identify() method is not qualified as const, so you can't call it on any const Brain object. This is the root of the problem that you are having trouble with.
In addition, there are many other problems with your code, as well:
Human::humanBrain is not a pointer, so using new to construct it is wrong. And, you don't need a pointer to get the address of a variable anyway. Nor do you actually need a pointer to the member at all in this project.
Human lacks a getBrain() method, so bob.getBrain() in main() will not compile, per the instructions.
Human::identify() is calling humanBrain.identify(), which returns a std::string as it should, but is then assigning that string to a local Brain variable, which is wrong (not to mention, you are not even using that variable for anything afterwards). The instructions clearly state that Human::identity() should simply call Brain::identify() and return its result, but you are not doing that.
Brain::identify() is printing the address of its local variable bPtr rather than printing the address of the Brain object that identify() is begin called on, per the instructions.
With all of that said, try something more like this instead:
Human.h
#pragma once
#include "Brain.h"
#include <string>
class Human
{
const Brain humanBrain;
public:
Human() = default;
std::string identify() const;
const Brain& getBrain() const;
};
Human.cpp
#include "Human.h"
std::string Human::identify() const
{
return humanBrain.identity();
}
const Brain& Human::getBrain() const
{
return humanBrain;
}
Brain.h
#pragma once
#include <string>
class Brain
{
int age;
std::string gender;
public:
Brain();
std::string identify() const;
};
Brain.cpp
#include "Brain.h"
#include <sstream>
Brain::Brain()
{
age = 10;
gender = "male";
}
std::string Brain::identify() const
{
std::ostringstream test;
test << "Brain Identify: 0x" << this;
return test.str();
}

C++ - Invalid operands to binary expression 'basic_ostream<char>'

I have an 'IntList' class with a dynamic array of integers, but the following fragment of test code gives me troubles:
main.cpp
#include <iostream>
#include "IntList.hpp"
using std::cout;
using std::endl;
int main(int argc, const char * argv[]) {
IntList list{};
cout << "list-1 -> " << list << endl;
return 0;
}
IntList.hpp:
#ifndef IntList_hpp
#define IntList_hpp
#include <stdio.h>
using std::ostream;
class IntList
{
public:
int *dynarray;
int capacity;
int used;
IntList();
void pushBack(int x);
int getCapacity();
void print(ostream& sout);
};
#endif
IntList.cpp
#include <iostream>
#include "IntList.hpp"
using std::cout;
using std::endl;
using std::string;
using std::ostream;
IntList::IntList()
{
int capacity = 1;
int used = 0;
int *dynarray = new int[capacity];
}
ostream& operator<<(ostream& sout, const IntList& list)
{
for (int i = 0; i < list.used; ++i)
sout << list.dynarray[i] << " ";
return sout;
}
From what I understood, I tried to overload the << operator with this:
invalid operands to binary expression ('ostream' (aka 'basic_ostream<char>') and 'ostream')
but I don't know where I get it wrong because XCode gives me this error:
Invalid operands to binary expression ('basic_ostream<char>' and 'IntList')
Any idea how to solve this ?
It appears (from the fragments you have shown) that there is no declaration of your << override in the header file (IntList.hpp). Thus, the code in your main function is not (and cannot be) aware of that override, which is provided in a separate source file.
You need to add a declaration of that override function in the header (tyically, just after the class definition), like this:
// Declaration (prototype) of the function for which the DEFINITION is provided elsewhere
extern ostream& operator<<(ostream& sout, const IntList& list);
Further, your IntList constructor has some serious faults. In it, you are assigning values to three local variables (whose data will be completely lost when the constructor finishes). Those variables are hiding the member variables with the same names. Use this, instead (i.e. remove the int declaration specifiers):
IntList::IntList()
{
// int capacity = 1; // This declares a local variable that hides the member!
capacity = 1;
used = 0;
dynarray = new int[capacity];
}

Re-declaration error when using a prior variable in anonymous instance creation

g++ gives a re-declaration error when using previously declared variable in anonymous instance creation.
I have the following code in my "weird.cpp" source file:
#include <iostream>
int main()
{
int i = 0;
int j = int ( i );
int ( i );
}
The error i am getting is,
weird.cpp: In function ‘int main()’:
weird.cpp:7: error: redeclaration of ‘int i’
weird.cpp:5: error: ‘int i’ previously declared here
I have tried this in mac and linux with versions 4.2 and 4.7 respectively. I have also tried with other types instead of int. The result is the same error. Can anyone help me understand this problem? Thanks.
First of all, the parentheses you're using here don't do anything.
int i = 0;
int j = int(i); // This is casting i to an int. It's already an int.
int j = i; // This does the same as the last line.
int (i); // This is redeclaring an int named i, which had already been done.
int i; // This is the same as the last line.
What you are saying about an object accepting an int in it's constructor doesn't make sense.
struct A { A(int) {} };
int i;
A obj(i); // A instance named obj which takes integer i as constructor argument.
I don't really understand what you're trying to achieve here, perhaps this?
int i = 0;
int j = i;
{
int i; // In another scope, shadowing the first i for scope duration.
}
You could be forgiven for being confused by this, it's a case of C++'s context-sensitive nature and how that is interpreted by the compiler.
int (i);
is being treated as a declaration of "i" (and since you already have a variable called i in this scope and have not enabled -Wno-shadow, it's not allowing this).
Contrast with the following case, which doesn't compile: (see http://ideone.com/QuwnTC)
#include <iostream>
class Bark {
public:
Bark(const char* msg, const char*) {
std::cout << "Hear ye, hear ye. " << msg << std::endl;
}
};
void bark(const char* i) {
Bark (i); // error here.
}
int main(int argc, const char* argv) {
bark("wtf");
}
It complains that Bark (i) shadows "i"s declaration.
However, both of the following DO compile: http://ideone.com/dcGMET
void bark(const char* i) {
Bark (i + 1);
}
or having two arguments inside the parenthesis: (http://ideone.com/tMzSY9)
#include <iostream>
class Bark {
public:
Bark(const char* msg, const char*) {
std::cout << "Hear ye, hear ye. " << msg << std::endl;
}
};
void bark(const char* i) {
Bark (i, NULL);
}
int main(int argc, const char* argv) {
bark("wtf");
}
Clearly, the treatment of "type (name)" here is some sort of special case, and you might want to raise this with the compiler developers.

How can I initialize char arrays in a constructor?

I'm having trouble declaring and initializing a char array. It always displays random characters. I created a smaller bit of code to show what I'm trying in my larger program:
class test
{
private:
char name[40];
int x;
public:
test();
void display()
{
std::cout<<name<<std::endl;
std::cin>>x;
}
};
test::test()
{
char name [] = "Standard";
}
int main()
{ test *test1 = new test;
test1->display();
}
And sorry if my formatting is bad, I can barely figure out this website let alone how to fix my code :(
If there are no particular reasons to not use std::string, do use std::string.
But if you really need to initialize that character array member, then:
#include <assert.h>
#include <iostream>
#include <string.h>
using namespace std;
class test
{
private:
char name[40];
int x;
public:
test();
void display() const
{
std::cout<<name<<std::endl;
}
};
test::test()
{
static char const nameData[] = "Standard";
assert( strlen( nameData ) < sizeof( name ) );
strcpy( name, nameData );
}
int main()
{
test().display();
}
Your constructor is not setting the member variable name, it's declaring a local variable. Once the local variable goes out of scope at the end of the constructor, it disappears. Meanwhile the member variable still isn't initialized and is filled with random garbage.
If you're going to use old-fashioned character arrays you'll also need to use an old-fashioned function like strcpy to copy into the member variable. If all you want to do is set it to an empty string you can initialize it with name[0] = 0.
Since you are using C++, I suggest using strings instead of char arrays. Otherwise you'd need to employ strcpy (or friends).
Also, you forgot to delete the test1 instance.
#include <iostream>
#include <string>
class test
{
private:
std::string name;
int x;
public:
test();
void display()
{
std::cout<<name<<std::endl;
}
};
test::test()
{
name = "Standard";
}
int main()
{
test test1;
test1.display();
std::cin>>x;
}
Considering you tagged the question as C++, you should use std::string:
#include <string>
class test
{
private:
std::string name;
int x;
public:
test();
void display()
{
std::cout<<name<<std::endl;
std::cin>>x;
}
};
test::test() : name("Standard")
{
}
c++11 actually provides two ways of doing this. You can default the member on it's declaration line or you can use the constructor initialization list.
Example of declaration line initialization:
class test1 {
char name[40] = "Standard";
public:
void display() { cout << name << endl; }
};
Example of constructor initialization:
class test2 {
char name[40];
public:
test2() : name("Standard") {};
void display() { cout << name << endl; }
};
You can see a live example of both of these here: http://ideone.com/zC8We9
My personal preference is to use the declaration line initialization because:
Where no other variables must be constructed this allows the generated default constructor to be used
Where multiple constructors are required this allows the variable to be initialized in only one place rather than in all the constructor initialization lists
Having said all this, using a char[] may be considered damaging as the generated default assignment operator, and copy/move constructors won't work. This can be solved by:
Making the member const
Using a char* (this won't work if the member will hold anything but a literal string)
In the general case std::string should be preferred

"Warning: Can't find linker symbol for virtual table for value XXX value" using GCC and GDB (CodeBlocks)

I'm getting a runtime error ("memory can't be written") that, after inspection through the debugger, leads to the warning in the tittle.
The headers are the following:
componente.h:
#ifndef COMPONENTE_H
#define COMPONENTE_H
using namespace std;
class componente
{
int num_piezas;
int codigo;
char* proovedor;
public:
componente();
componente(int a, int b, const char* c);
virtual ~componente();
virtual void print();
};
#endif // COMPONENTE_H
complement.h implementation
#include "Componente.h"
#include <string.h>
#include <iostream>
componente::componente()
{
num_piezas = 0;
codigo = 0;
strcpy(proovedor, "");
//ctor
}
componente::componente(int a = 0, int b = 0, const char* c = "")
{
num_piezas = a;
codigo = b;
strcpy(proovedor, "");
}
componente::~componente()
{
delete proovedor;//dtor
}
void componente::print()
{
cout << "Proovedor: " << proovedor << endl;
cout << "Piezas: " << num_piezas << endl;
cout << "Codigo: " << codigo << endl;
}
teclado.h
#ifndef TECLADO_H
#define TECLADO_H
#include "Componente.h"
class teclado : public componente
{
int teclas;
public:
teclado();
teclado(int a, int b, int c, char* d);
virtual ~teclado();
void print();
};
#endif // TECLADO_H
teclado.h implementation
#include "teclado.h"
#include <iostream>
teclado::teclado() : componente()
{
teclas = 0;//ctor
}
teclado::~teclado()
{
teclas = 0;//dtor
}
teclado::teclado(int a = 0, int b = 0, int c = 0, char* d = "") : componente(a,b,d)
{
teclas = c;
}
void teclado::print()
{
cout << "Teclas: " << teclas << endl;
}
The main method where I get the runtime error is the following:
#include <iostream>
#include "teclado.h"
using namespace std;
int main()
{
componente a; // here I have the breakpoint where I check this warning
a.print();
return 0;
}
BUT, if instead of creating an "componente" object, I create a "teclado" object, I don't get the runtime error. I STILL get the warning during debugging, but the program behaves as expected:
#include <iostream>
#include "teclado.h"
using namespace std;
int main()
{
teclado a;
a.print();
return 0;
}
This returns "Teclas = 0" plus the "Press any key..." thing.
Do you have any idea why the linker is having troube with this? It doesn't show up when I invoke the virtual function, but before, during construction.
Two errors that I can see:
strcpy(proovedor, ""); // No memory has been allocated to `proovedor` and
// it is uninitialised.
As it is uninitialised this could be overwriting anywhere in the process memory, so could be corrupting the virtual table.
You could change this to (in both constructors):
proovedor = strdup("");
Destructor uses incorrect delete on proovedor:
delete proovedor; // should be delete[] proovedor
As this is C++ you should considering using std::string instead of char*.
If you do not change to std::string then you need to either:
Implement a copy constructor and assignment operator as the default versions are incorrect if you have a member variable that is dynamically allocated, or
Make the copy constructor and assignment operator private to make it impossible for them to be used.
Another source of this same message is that gdb can get confused by not-yet-initialized variables. (This answers the question title, but not the OP's question, since a web search led me here looking for an answer.)
Naturally, you shouldn't have uninitialized variables, but in my case gdb attempts to show function local variables even before they are declared/initialized.
Today I'm stepping through another developer's gtest case and this message was getting dumped to output every time the debugger stopped. In this case, the variable in question was declared on ~line 245, but the function started on ~line 202. Every time I stopped the debugger between these lines, I received the message.
I worked around the issue by moving the variable declaration to the top of the function.
For reference, I am testing with gdb version 7.11.1 in QtCreator 4.1.0 and I compiled with g++ version 5.4.1