In the below program i have used two classes , and i am trying to relate the with aggregation, i have declare class A as private in class B, and with the help of constructor i am initizing base address of class A object to private member of class B object that is (A object). i am trying to pass the class A values to class B usng parametrized constructor, but i am getting garbage values like,
#include <iostream>
using namespace std;
void create (B * &obj2, int siz)
{
std::cout << obj2[0].get_nn (); //this will run fine
for (int i = 0; i < siz; i++)
obj2[i] = B (10, "pranjal"); //this will also run fine
std::cout << obj2[0].get_nn ();
}
// same line printing again, this will not give output
// ***************************************
void display ()
{
std::cout << object.get_data () << object.get_stringdata ();
}
// giving garbage values
// why is it happening
// *********************************program
// ************************************** enter code here
// Online C++ compiler to run C++ program online
class A {
int rool;
string name;
public:
A () { };
A (int a, string name);
int get_data () {
return rool;
}
string get_stringdata () {
return this->name;
}
};
A::A (int a, string name)
{
this->rool = a;
this->name = name;
}
void getdetails (A * obj)
{
for (int i = 0; i < 3; i++)
obj[i] = A (20, "pranjal");
}
class B {
int bbb;
string name;
A object;
public:
B () {};
B (A s) {
object = s;
}
string get_nn () {
return object.get_stringdata ();
}
B (int a, string b);
void display () {
std::cout << object.get_data () << object.get_stringdata ();
}
};
void dis (B * obj2)
{
for (int i = 0; i < 2; i++) {
obj2[i].display ();
}
}
void create (B * &obj2, int siz)
{
std::cout << obj2[0].get_nn ();
for (int i = 0; i < siz; i++)
obj2[i] = B (10, "pranjal");
std::cout << obj2[0].get_nn () << "sd";
}
B::B (int a, string b)
{
bbb = a;
name = b;
}
int main ()
{
A *obj = new A[3];
getdetails (obj);
B *obj2 = new B[3];
for (int i = 0; i < 3; i++) {
obj2[i] = B (obj[i]);
}
create (obj2, 3);
dis (obj2);
obj2->display ();
return 0;
}
In create, you fully replace the previous B objects with brand new ones using the 2 parameters constructor... which just leaves the A object member default initialized.
What could be done to fix?
Pass the parameters of B to A ctor:
B::B (int a, string b): object(a, b)
{
bbb = a;
name = b;
}
That way you initialize the A object member with the same parameters as its parent
Reset the A object member to its previous value:
void create (B * &obj2, int siz)
{
std::cout << obj2[0].get_nn (); //this will run fine
for (int i = 0; i < siz; i++) {
A old = obj2[i].object;
obj2[i] = B (10, "pranjal"); //this will also run fine
obj2[i].object = old;
}
std::cout << obj2[0].get_nn ();
}
But as it requires accesses to private members, create should be declared friend in B class:
class B {
...
friend void create (B * &obj2, int siz);
};
void create(B *&obj2,int siz)
{
std::cout<<obj2[0].get_nn(); //this will run fine
for(int i=0;i<siz;i++)
obj2[i]=B(10,"pranjal");
std::cout<<obj2[0].get_nn(); // same line printing again, this will not give output
}
Of course it won't: B(int, std::string) does not call a constructor of A explicitly, so A's default constructor is called. This implicitly calls name's default constructor, too, which will create an empty string.
For a similar reason you get garbage values: Your default constructor does not assign a value to rool, thus leaves it uninitialised; it will remain at the value that was there in memory before, which ever it was, which is what you consider 'garbage'.
This occurs because with obj2[i] = B(10,"pranjal") a new object is created and then copied into the target object (with optimisations, can be created directly in place, but obviously you cannot rely on).
Fix your constructor of A to assign a value to rool and the problem should go away. You might chose a non-zero value to have a more clearly visible effect:
A() : rool(1977) { }
Alternatively you can provide provide a default value to rool (requires C++11):
int rool = 1977;
That can be convenient especially if you have a larger number of constructors.
In general: You should not leave primitive types of any of your objects uninitialised to avoid similar problems.
Related
code looks like this
#include<iostream>
class A
{
public:
int* a;
char name;
A(char _n = 'N')
{
a = 0;
name = _n;
}
A(int _a, int _b, char _n = 'N')
{
name = _n;
a = new int[2]{ _a, _b };
}
~A()
{
std::cout << "deleting object..." << name << "\n";
delete[] a;
}
//
void operator=(A b)
{
std::cout << "cleanup begin\n";
delete[] a;
a = new int[] {b.a[0], b.a[1]};
}
//
A Copy()
{
if (a == 0) return *new A();
A* _r = new A(a[0], a[1], name + 1);
return *_r;
}
};
//
int main()
{
A d{0, 1, 'T'};
{
A Z(0, 1);
Z = Z.Copy();
}
std::cout << "check\n";
return 0;
}
I want Z = Z.Copy() to work but instead it triggers a breakpoint in delete_scalar.
From what i understand, the overloaded = should free the memory that is allocated to member a, after which it should allocate new memory and copy the integers by value, then destroying b.
Even so, object Z from the nameless scope has its destructor called twice, leading to the breakpoint trigger.
All that I want is to be able to do something like this:
x = (x - y) * z + y;
where I can overload = for x to assign to it the result of overloaded object operations (x and y are custom vector3 instances, z is a custom Matrix4 instance, Matrix4 contains a float*, if that's relevant).
So, what is the problem and how do I solve it?
Following my question, I coded a simple tool to compute a root using the bisection method, which is working fine. Here is the code:
roots.h
#ifndef ROOTS_H
#define ROOTS_H
class FunctRoots {
public:
// default constructor
FunctRoots();
// destructor
virtual ~FunctRoots();
// return the error
virtual double evaluate(double x);
};
class Roots{
private:
double tol=1e-5;
int max_iter=100;
double a, b;
double fa=0.0;
double fb=0.0;
public:
// default constructor
Roots();
// destructor
virtual ~Roots();
// set tolerance
void set_tolerance(double tolerance);
// set the search space
void set_search_space(double a, double b);
// bracketing
void bracketing(FunctRoots& problem, double start, double step);
// bisection method
double bisection(FunctRoots& problem);
};
#endif
roots.cpp
#include "roots.h"
#include "iostream"
#include "cmath"
// define the template for the function
FunctRoots::FunctRoots () {}
FunctRoots::~FunctRoots () {}
double FunctRoots::evaluate(double x){
return 0.0;
};
// Roots class
Roots::Roots() {}
Roots::~Roots() {}
// set search space
void Roots::set_search_space(double a, double b){
this->a = a;
this->b = b;
}
// set tolerance
void Roots::set_tolerance(double tolerance){
this->tol = tolerance;
}
// bracketing
void Roots::bracketing(FunctRoots& problem, double start, double step){
// set initial boundary
this->a = start;
this->fa = problem.evaluate(this->a);
// main loop
this->b = start;
for (int iter = 0; iter < max_iter; iter++) {
// update upper boundary
this->b += step;
this->fb = problem.evaluate(this->b);
// check if a root exists
if (this->fa*this->fb < 0) break;
// update lower bound
this->a = this->b;
this->fa = this->fb;
}
// check boundaries
if (this->a > this->b){
double temp;
temp = this->a;
this->a = this->b;
this->b = temp;
temp = this->fa;
this->fa = this->fb;
this->fb = temp;
}
}
// bisection method
double Roots::bisection(FunctRoots& problem){
// variables declaration
double fx, x;
// compute errors
if (fabs(this->fa) < 1e-12){
this->fa = problem.evaluate(this->a);
}
// main loop
x = 0;
for (int iter = 0; iter < max_iter; iter++) {
// compute solution
x = (a+b)/2.0;
fx = problem.evaluate(x);
// print on screen
std::cout << "iter=" << iter << "\n";
std::cout << "a=" << a << "\n";
std::cout << "b=" << b << "\n";
std::cout << "x=" << x << "\n";
std::cout << "fx=" << fx << "\n\n";
// stop criterion
if (fabs(fx) < this->tol) break;
// update boundaries
if (this->fa*fx < 0){
this->b = x;
}else{
this->a = x;
this->fa = fx;
}
}
// function return
return x;
}
main.cpp
#include "roots.h"
#include "cmath"
class Problem: public FunctRoots{
private:
double value;
public:
Problem(double value){
this->value = value;
}
double evaluate(double x) {
return pow(cos(x),2)+this->value-x;
}
};
int main(){
Problem problem(6);
Roots roots;
//roots.set_search_space(5, 10);
roots.set_tolerance(1e-7);
roots.bracketing(problem, 0,0.1);
roots.bisection(problem);
return 0;
}
Now, the question is this: how can I make my main looks like this?
int main(){
Problem problem(6);
Roots roots;
roots.set_problem(problem) // <----NEW
//roots.set_search_space(5, 10);
roots.set_tolerance(1e-7);
roots.bracketing(0,0.1); // <---- problem is not here anymore
roots.bisection(); // <---- problem is not here anymore
return 0;
}
Basically, I would like to define my problem once and for all just after initializing the solver so that I don't need to give it as input to the functions anymore, however considering that the function evaluate is defined in FunctRoots but then overridden in Problem.
I would like to define my problem once and for all just after initializing the solver …
You can add a reference to a FunctRoots object as a member of your Roots class:
class Roots {
private:
FunctRoots& problem;
double tol = 1e-5;
//...
However, rather than initializing this "just after initializing the solver", you would need to intialize it at the time of creating that solver (i.e., pass it as a parameter to the constructor and initialize the member variable in an initializer list). So, your Roots constructor would then look like this:
Roots::Roots(FunctRoots& fr) : problem{ fr } {}
You can then (as you desire) remove the reference to the Problem object in your bracketing and bisection methods, and your main would look like:
int main() {
Problem problem(6);
Roots roots(problem); // Initializes reference member at construction
roots.set_tolerance(1e-7);
roots.bracketing(0, 0.1); // <---- problem is not here anymore
roots.bisection(); // <---- problem is not here anymore
return 0;
}
Note that such reference members must be initialized at object construction time; they cannot then be reassigned to refer to different objects. Also note that polymorphism works with references, just as it does with pointers.
How to define a class member with a reference
It's as simple as that, just declare a member reference and create a constructor to initialize it:
class Member{};
class MyClass{
Member& member;
public:
MyClass(Member& m) : member(m) {}
};
int main(){
Member m;
MyClass cl(m);
}
Note that the lifetime of Member must be at least the same as MyClass otherwise you will end up with a dangling referece.
In this case, I think your root class should either
have member variable "problem", and initialize it when you call roots.set_problem(problem).
like
class Roots {
private:
Problem *myProblem;
public:
void set_problem(Problem &problem){
myProblem = new Problem(problem.value)
}
}
or have other variable members that could store value you give with roots.set_problem(problem).
Problem
I want to create a function inside a class which function2 will use the result generated from function1. I have a small code snippet where I tried to make it easy to understand.
#include <stdio.h>
class GreaterSmaller {
public:
int greater, smaller;
};
GreaterSmaller findGreaterSmaller(int a, int b)
{
GreaterSmaller s;
if (a > b) {
s.greater = a;
s.smaller = b;
}
else {
s.greater = b;
s.smaller = a;
}
return s;
}
GreaterSmaller print()
{
GreaterSmaller s;
std::cout << s.greater << s.smaller << std::endl;
}
int main()
{
int x = 4;
int y = 3;
GreaterSmaller result;
result = findGreaterSmaller(x, y);
result = print(); // I want it to print 4 & 3
return 0;
}
P.s Just wanted to mention I am not trying to print the result in the function2 I have created that for a demo.
Define the second method as taking an argument of the first type, and pass it when you call it, as such:
void print(GreaterSmaller &s)
{
std::cout << s.greater << s.smaller << std::endl;
}
print(result); // I want it to print 4 & 3
It might be that I have coded my class incorrectly, but when I use the move constructor instead of the copy cotr (as one of the overloads not instead to be precise), my program crushes:
For example:
class Sample
{
int a;
int **b;
//constructor declarations
}
And in the .cpp file:
Sample::Sample(Sample &&other)
: a(a), b(b)
{
for (int i = 0; i < a; i++)
other.b[i] = nullptr;
other.b = nullptr;
other.a = 0;
}
How to fix this issue?
Here is how you could move the values:
#include <utility>
#include <iostream>
class Sample
{
int a;
int **b;
public:
Sample(int a, int** b) : a{a}, b{b} {}
Sample(Sample &&other);
// still missing a destructor that will get rid of the new'd ints
void print();
};
Sample::Sample(Sample &&other)
: a(other.a), b(other.b)
{
//for(int i = 0; i < a; i++)
// other.b[i] = nullptr; // this should not be done, the new b has a pointer to these values
other.b = nullptr;
other.a = 0;
}
void Sample::print()
{
if(a == 0 && b == nullptr)
std::cout << "this object is empty!";
for(size_t i{0}; i < a; ++i) {
std::cout << *b[i] << " ";
}
std::cout << '\n';
}
int main()
{
Sample s{5,{new int*[5]{new int{0}, new int{1}, new int{2}, new int{3}, new int{4}}}};
auto c{std::move(s)};
// c now has c.b as a pointer an array of pointers
s.print();
c.print();
return 0;
}
Ill just recap my comment above and put it as an answer. You copied 'b' pointer but you modified the values that pointer points to. The new object will get correct pointer 'b' but the value that pointer points to is modified as well, in this case it will point to number zero. You are using pointer to a pointer so at some point your new object might try to dereference the pointers and as a result of a dereferencing a null pointer bad things happen.
I am wondering how to sort an array that contains objects of a custom class. I am trying to apply different sorting algorithms but in the swapping something goes wrong.
Here is my Code:
class RaceCar
{
private:
char* _brand;
char* _model;
double _price;
int _horse_power;
public:
//Other code
RaceCar(const RaceCar& rc):_price(rc._price), _horse_power(rc._horse_power)
{
_brand = new char[strlen(rc._brand)+1];
strcpy(_brand, rc._brand);
_model = new char[strlen(rc._model)+1];
strcpy(_model,rc._model);
}
RaceCar& operator=(const RaceCar& rc)
{
if(this != &rc)
{
delete _brand;
delete _model;
_brand = new char[strlen(rc._brand)+1];
strcpy(_brand, rc._brand);
_model = new char[strlen(rc._model)+1];
strcpy(_model, rc._model);
_price = rc._price;
_horse_power = rc._horse_power;
}
return *this;
}
bool operator<(const RaceCar& rc)
{
return (this->_price/this->_horse_power) > (rc._price/rc._horse_power);
}
//Other code
};
And this is the class that contains an array of RaceCars. I am trying to implement SortCars() method that orders the RaceCar objects inside the array of cars:
class RaceCarGarage
{
private:
RaceCar* _cars;
int _max_cars;
int _curr_occupied;
public:
RaceCarGarage():_cars(NULL), _max_cars(0),_curr_occupied(0){}
RaceCarGarage(const RaceCar& car, int max_cars)
:_max_cars(max_cars), _curr_occupied(0)
{
_cars = new RaceCar[_max_cars];
}
~RaceCarGarage()
{
delete _cars;
}
void AddCar(const RaceCar& car)
{
if(_curr_occupied < _max_cars)
{
_cars[_curr_occupied] = car;
_curr_occupied += 1;
}
}
void DisplayCars()
{
if(_curr_occupied > 0)
{
for(int i=0 ; i<_curr_occupied ; i++)
{
cout<<(i+1)<<". ";
(_cars+i)->Display();
}
}
}
void SortCars()
{
if(_curr_occupied > 1)
{
for(int i=0 ; i<_curr_occupied ; i++)
{
for(int j = i+1 ; j<_curr_occupied ; j++)
{
if(_cars[j]<_cars[i])
{
RaceCar buffer = _cars[i];
_cars[i] = _cars[j];
_cars[j] = buffer;
}
}
}
}
}
};
The problem with the swapping is that you use the traditional way to do:
temp = a // operator=
a = b // operator=
b = temp; // operator=
However, if you write:
RaceCar temp = a; // Copy constructor gets called (see comment on standard)
a = b; // operator=
b = temp; // operator=
The default copy constructor, just copies member by member, so just copies your pointer. So at the end, your temp and your will try to delete twice the same object pointed to.
Remark on assignment initializer :
For a type T, a statement in form T a = b; is an initializer.
The ISO standard C++ in section 12.6.1 point 1 explains "a single assignment-expression can be specified as an initializer using the = form of initialization. Either direct-initialization semantics or copy-initialization semantics apply;"