How can I initialize struct data members in Constructor? - c++

I am using data.h file which have the following code
#ifndef __DATA_h_INCLUDED__
#define __DATA_h_INCLUDED__
#include "string"
struct data {
std::string location="";
int year = 0, month = 0;
data();
data(std::string location, int year, int month);
};
#endif
and the data.cpp file looks like this
#include "data.h"
#include "string"
using namespace std;
data::data() {
//initialize the data members (location,year,month)
}
data::data(std::string loc, int year, int month) {
//initialize the data members (location,year,month)
}
in some other .cpp file how can i get these values and initialize these values.
node.h
struct Node {
data d;
Node(std::string id, int year, int month);
};
node.cpp
Node::Node(string id, int year, int month){
// here i want to initialize 'data'
}
print.cpp
Node* node;
cout<<node->data->location;

They are already initialized for the default coinstructor (which shoudl proably be =default instead).
Then just use the initialization list:
data::data(std::string loc, int year, int month):loc(std::move(loc)), year(year), month(month) {
}
Include string properly as well:
#include <string>

in your "data.cpp", you can initialize the members like this:
#include "data.h"
#include "string"
using namespace std;
data::data() : year(0), month(0) {
//initialize the data members (location,year,month)
//in fact, 'location' donot need initialization,
//because the member will be constructed first as
//a empty string before give control to user-defined constructor.
location = "";
}
data::data(std::string loc, int _year, int _month)
year(_year), month(_month) {
//initialize the data members (location,year,month)
location = loc; // or location.assign(loc);
}
when you use the structure in other cpp file, you may use is like this:
#include "data.h"
data x; //call default constructor: data();
//since struct 's member is implicitly public,
//you can access them from outside of its defination.
x.location = "your location";
x.location.assign("some other place");
x.location.append("etc");
x.year = 2018;
x.month = 11;

Initializing data in constructor is done like this:
data::data() :
location(""), year(0), month(0)
{
}
data::data(std::string loc, int year, int month) :
location(loc), year(year), month(month)
{
}
In some other cpp file, for example, main.cpp, you can use this like that:
#include <iostream>
#include "data.h"
int main()
{
// initializing
data obj("NY", 2018, 11);
// using
std::cout << "Year: " << obj.year << std::endl;
std::cout << "Month: " << obj.month << std::endl;
std::cout << "Loc: " << obj.location << std::endl;
// setting properties
obj.year = 2100;
obj.month = 1;
std::cout << "Year: " << obj.year << std::endl;
std::cout << "Month: " << obj.month << std::endl;
// initializing by default values
data obj2();
}

Don't overcomplicate this. If you start coding, don't split your code up in too many files.
Other than that, learn about struct member initialization. Either on this site or at your favorite documentation page.
For member access you use the arrow-operator when you have a pointer to an object, vs. the dot-operator that you use when you have the object directly. For further reading:
What is the difference between the dot (.) operator and -> in C++?
https://en.cppreference.com/w/cpp/language/operator_member_access#Built-in_member_access_operators
Here's example code:
#include <iostream>
struct data {
int x_;
// use member initialization list to init the data value directly
data(int x) : x_(x) {}
};
struct node {
data data_;
// use member initialization list to init the data value directly
node(int x) : data_(x) {}
};
int main() {
// create object
node n(42);
// acquire pointer to object
node *p = &n;
// use arrow to access member with pointer, use dot to access with object
std::cout << p->data_.x_ << '\n';
}
The output is:
$ g++ test.cc && ./a.out
42
And because it seems you might be into implementing some sort of data structure, you might also want to learn about object lifetime and ownership issues with manual memory management. So some references for further education:
What is a smart pointer and when should I use one?
CppCon 2016: Herb Sutter “Leak-Freedom in C++... By Default.”

Related

C++ variables passed to constructor are not being passed correctly

I am just trying to get set up with some simple classes in C++. I am trying to create an Order type that takes in a price (double), quantity (int) and a style (std::string)
Here is my order.h
#ifndef ORDER_H
#define ORDER_H
#include <string>
#include <iostream>
class Order {
private:
double limit_price;
int quantity;
std::string style;
public:
Order();
Order(double price, int quantity, std::string style);
void print_price();
void print();
};
#endif
My implementation in order.cpp.
#include "order.h"
#include <iostream>
Order::Order(){
limit_price = 0;
quantity = 0;
style = "bid";
}
Order::Order(double price, int quantity, std::string style){
limit_price = price;
quantity = quantity;
style = style;
}
void Order::print_price(){
std::cout << "limit_price = " << limit_price << std::endl;
}
void Order::print(){
std::cout << style << " " << quantity << "#" << limit_price << std::endl;
}
And here is my simple test code.
#include "order.cpp"
#include <iostream>
#include <string>
int main(){
Order null_order = Order();
Order order = Order(12.3, 2, "bid");
null_order.print();
order.print();
return 0;
}
However, for a reason I don't understand, when I run I run my test file, instead of getting
bid 0#0
bid 2#12.3
As I would have expected, I get something like the following.
bid 0#0
-1722935952#12.3
Where the large negative number changes on each run.
In your constructor the name of the parameters shadow the members:
Order::Order(double price, int quantity, std::string style){
limit_price = price;
quantity = quantity;
style = style;
}
What do you think quantity is in the second line? Why should it something different on the left hand side than on the right hand side?
quantity refers to the parameter.
You can prepend this-> to members to disambiguate, though thats rather uncommon. In such cases, better rename either of them.
Anyhow you should initialize members rather than assign in the body of the constructor. Members are initialized before the body of the constructor is executed. One way to initialize members is the member initializer list:
Order::Order(double p, int q, std::string s) : limit_price(p),quantity(q),style(s)
{ /* empty body */ }
And because in the initializer list there is no danger of ambiguity we can use the same name for parameters as for the members:
Order::Order(double limit_price, int quantity, std::string style) : limit_price(limit_price),quantity(quantity),style(style)
{}

How to create member objects by class constructor?

In my example I created a class Person which has a member object: struct data. This object contains data about person. Each time a Person-Object is created, also the data-object shall be initialized.
Observation: When adding object initializer to code (1) at class constructor I get failure message:
incomplete type is not allowedC/C++(70)
class person {
public:
struct data;
person() { /* (1) */
person::data myPersonData;
}
private:
};
So here is how I practice it now:
No struct object initialization myPersonData in class person constructor (class_person.hpp)
Create person object in main.cpp
Create myPersonData in main.cpp (I would like to save this
initialization and put it to class contructor)
The whole example looks like this:
// class_person.hpp
#include <iostream>
#include <string>
class person {
public:
struct data;
private:
};
struct person::data {
std::string name = "John";
int age = 42;
int weight = 75;
};
_
// main.cpp
#include <iostream>
#include "class_person.hpp"
void outputPersonData(person::data myPerson) {
std::cout << myPerson.name << "\n";
std::cout << myPerson.age << "years\n";
std::cout << myPerson.weight << "kg\n";
};
int main() {
person John;
person::data myPersonData;
outputPersonData(myPersonData);
getchar();
return 0;
}
You should put the definition of data inside the definition of person if you want a member of it. Something like this.
#include <string>
#include <iostream>
class person {
public:
struct data {
std::string name = "John";
int age = 42;
int weight = 75;
};
// This is just the definition the the class. We need the class
// to have a definition if we want to use a value of it in person
person() = default;
// Default constructors, give us a default constructed personData
// that uses the default values from the definition
person(data d) : personData(std::move(d)) {}
// Constructor that takes a personData object and uses it to
// initialize our member. std::move is to avoid uneccesary copying
void outputPersonData() const {
std::cout << personData.name << "\n";
std::cout << personData.age << "years\n";
std::cout << personData.weight << "kg\n";
}
data personData;
// This is the actual data member, now person contains
// a member named personData of type person::data
};
int main() {
person john;
person mike({"Mike", 47, 82});
john.outputPersonData();
mike.outputPersonData();
}

How to implement a class that has one of either two types for an arg

if I have a c++ class like:
class Student
{
public:
string name;
int assigned_number;
};
and I want to use either name or number but not both for each instance, is there a way to make this an Or type where only one of them is required?
If you are using C++17 or above, you can use std::variant from <variant>:
#include <iostream>
#include <variant> // For 'std::variant'
class Student
{
public:
std::variant<std::string, int> name_and_id;
};
int main() {
Student stud; // Create an instance of student
// Pass a string and print to the console...
stud.name_and_id = "Hello world!";
std::cout << std::get<std::string>(stud.name_and_id) << std::endl;
// Pass an integer and print to the console...
stud.name_and_id = 20;
std::cout << std::get<int>(stud.name_and_id) << std::endl;
}
std::variant is a new addition to C++17 and is intended to replace the unions from C and has exceptions in case of errors...
You can use union.
#include <string>
class Student
{
// Access specifier
public:
Student()
{
}
// Data Members
union
{
std::string name;
int assigned_number;
};
~Student()
{
}
};
int main()
{
Student test;
test.assigned_number = 10;
test.name = "10";
return 0;
}

Weird behavior with OOP and string pointers

Here's my code:
#include <iostream>
#include <string>
class Human
{
public:
std::string * name = new std::string();
void introduce();
};
void Human::introduce()
{
std::cout << "Hello, my name is " << Human::name << std::endl;
}
int main()
{
Human * martha;
martha->name = new std::string("Martha");
martha->introduce();
return 0;
}
Well, it's supposed to print a message out like:
"Hello, my name is Martha" but it doesn't print neither the "Hello, my name is" string or the "Martha" name. Why does it occur?
The fix is simple and is to completely remove all pointers; see the code below. There are a number of issues with your code that I could address in detail, including memory leaks, uninitialized variables, and general misuse of pointers, but it seems that you're possibly coming from a different language background and should spend time learning good practice and the important semantics and idioms in modern C++ from a good C++ book.
#include <iostream>
#include <string>
class Human
{
public:
std::string name;
void introduce();
};
void Human::introduce()
{
std::cout << "Hello, my name is " << name << std::endl;
}
int main()
{
Human martha;
martha.name = "Martha";
martha.introduce();
return 0;
}
Few modifications are required to the code.
Updated code along with the comments to the change made are included below.
#include <iostream>
#include <string>
class Human
{
public:
//Removed pointer to a string
//Cannot have an instantiation inside class declaration
//std::string * name = new std::string();
//Instead have a string member variable
std::string name;
void introduce();
};
void Human::introduce()
{
//Human::name not required this is a member function
//of the same class
std::cout << "Hello, my name is " << name << std::endl;
}
int main()
{
Human *martha = new Human();
//Assign a constant string to string member variable
martha->name = "Martha";
martha->introduce();
return 0;
}
As suggested by #alter igel - The Definitive C++ Book Guide and List would be a good place to start.
#include <iostream>
#include <string>
class Human {
public:
void Human(std::string* n) { name = n; }
void introduce();
private:
std::string* name;
};
void Human::introduce() {
std::cout << "Hello, my name is " << name << std::endl;
}
int main() {
Human* martha = new Human(new std:string("Martha"));
martha->introduce();
return 0;
}
Try that. The difference is that you don't initialise the variable in the class definition, and you initialise the name with the constructor. You can split the method definition out into it's own section, but it's only one line and is fine being inside the class definition.

Static Functions and class variables?

I have broken down my issue into a small simple program.
I have a class myclass I have created in a separate .cpp file "classes.cpp" and declared in the header file "classes.h". myclass contains a variable a of which is initialized when instantiated. This makes variable a = 5.
My overall goal is to create a class in a separate .cpp file declared in a .h file which I can create multiple instances of in my main() program. The problem I am having is this.
In my main() function I create an instance of myclass called first.
my main program shows the variable a is set to the number 5.
If I want to change that number using a static function (and it has to be a static function as this relates to something much bigger in another program I am writing). I call the static function directly and in that static_function I create an instance of myclass and call the non_static_function because static functions have no implicit 'this' connecting them to an object.
In my non_static_function I change the value to the number 8. The problem is that the value of variable 'a' in 'first' remains at 5 when I want it to be 8. I need to change the value using first->static_function(8) and not by first->a = 8. . How can I do this?
Code below:
**main.cpp**
#include <iostream>
#include "classes.h"
using namespace std;
int main()
{
myclass *first = new myclass();
cout << "Myclass variable a is = " << first->a << endl;
first->static_function(8); // trying to change myclass variable 'a' to 8.
cout << "But" << endl;
cout << "the actual value of a is still: " << first->a << endl;
}
**classes.h**
#ifndef CLASSES_H_INCLUDED
#define CLASSES_H_INCLUDED
class myclass
{
public:
int a;
myclass();
void non_static_function(int x);
static void static_function(int x);
};
#endif // CLASSES_H_INCLUDED
**classes.cpp**
#include <iostream>
#include <cstdlib>
#include "classes.h"
using namespace std;
myclass::myclass()
{
a = 5;
}
void myclass::non_static_function(int x)
{
a = x;
cout << "The value for variable 'a' was 5 but is now: " << a << endl;
}
void myclass::static_function(int x)
{
myclass *p = new myclass();
p->non_static_function(x);
}
If you want every instance of myclass to have its own a and you want to call a static function to change it then you need to pass the instance you want changed to the static function. A static function can only modify static members of a class or the members of an instance that is inside its scope. Non static member functions can change any variable that is a member of the class.
class Foo
{
private:
int bar;
public:
static void static_function(int value, Foo & foo) { foo.bar = value; }
void non_static_function(int value) { bar = value; }
};
int main()
{
Foo foo;
Foo::static_function(8, foo);
// now bar will have the value of 8
foo.non_static_function(20);
// now bar will have the value of 20
}
I have finally found a way to deal with this small problem. Above the 'myclass' definition in classes.cpp I declare a 'myclass' variable
myclass *tgt; . Then in my constructor for 'myclass' I just allocate the instantiated object to a my global myclass variable of which I can access from the myclass definition tgt = this; Now I can use tgt in my static function to call the non_static_function in my 'myclass' definition and it all works perfectly.
NathanOliver, you are correct in saying that I need a class instance but the way I have done it here suits my needs. Passing the instance of myclass is certainly another way of doing this but it would require a global function above my 'myclass' definition.
Thanks for the help.
**main.cpp**
#include <iostream>
#include "classes.h"
using namespace std;
int main()
{
myclass *first = new myclass();
cout << "Myclass variable a is = " << first->a << endl;
first->non_static_function(8); // trying to change myclass variable 'a' to 8.
cout << "But" << endl;
cout << "The actual value of a is still: " << first->a << endl;
myclass *second = new myclass();
cout << "For the 'second' class the variable a is: " << second->a << endl;
second->non_static_function(23);
cout << "After calling the static function from 'second' the value of a is: " << second->a << endl;
cout << "And first->a is still: " << first->a << endl;
}
**classes.h**
#ifndef CLASSES_H_INCLUDED
#define CLASSES_H_INCLUDED
class myclass
{
public:
int a;
myclass();
void non_static_function(int x);
static void static_function(int x);
};
#endif // CLASSES_H_INCLUDED
**classes.cpp**
#include <iostream>
#include <cstdlib>
#include "classes.h"
using namespace std;
myclass *tgt; // *Add a global myclass variable above the myclass
definition*
myclass::myclass()
{
tgt = this; // *In the constructor allocate the instantiated class
//from main() to "tgt" .*
a = 5;
}
void myclass::non_static_function(int x)
{
a = x;
// Now see that the value of a is changed.
cout << "The value for variable 'a' was 5 but is now: "<< this->a << endl;
}
void myclass::static_function(int x)
{
tgt->non_static_function(x);
}