I've just started learning C++ and stumbled across this problem..
I've written this abstract class with pure virtual destructor:
#ifndef ANIMAL
#define ANIMAL
#include <string>
using namespace std;
class Animal {
public:
Animal();
virtual ~Animal() = 0;
Animal(string name, int age);
virtual string says() = 0;
void setName(string name);
void setAge(int age);
string getName() const;
int getAge() const;
private:
int _age;
string _name;
};
inline Animal::~Animal() { }
Created dynamically and destroyed like this...
Animal** animalArray = new Animal*[10];
animalArray[0] = new Dog(name, age);
animalArray[1] = new Cat(name, age);
animalArray[2] = new Owl(name, age);
delete[] animalArray;
and I am left wondering if an Animal object is created dynamically and then destroyed, will the _age and _name members get destroyed properly since the destructor for Animal class is empty? If so, why?
Thanks :D
In the example you posted, you're actually not destroying everything correctly. In the line
delete[] animalArray;
you are deleting an array of Animal*s. Note that this does not automatically destroy the things being pointed to! You would have to do:
for(int i = 0; i < 3; ++i)
delete animalArray[i];
delete[] animalArray;
This destroys each element, then destroys the container.
Now, your actual question is asking whether the private member variables are going to be cleanly destroyed. The answer is yes--after your destructor runs, any statically allocated variables' destructors will also be called by the compiler. It is their obligation to clean up after themselves. When you're doing polymorphism as in your example, the (empty) destructor Animal::~Animal will indeed be called.
Note that this carries the same warning as the code above: if you instead have
string* _name;
that you dynamically allocate in the constructor (with new), then the string* will be destroyed, but the pointed to string will not be. So in that case, you would have to manually call delete to properly clean up.
yes they will. By making the Animal destructor virtual (or pure virtual in your case, doesn't matter regarding your question) you make sure that everything is properly destroyed when using Animal as a base class.
The destructor of Animal will call the destructor for each of it's members in reverse initialization order (i.e. it will destroy _name first and _age afterwards) and thereby makes sure that everything is properly freed.
According to Herb Sutter you cannot instantiate a class with a pure virtual destructor unless it also has a body. The reason is that any derived class will need to call that destructor after its own destructor is finished.
We can verify this with at least one compiler: http://ideone.com/KcwL8W
#include <string>
class Animal
{
public:
virtual ~Animal() = 0;
std::string _name;
};
class Dog : public Animal
{
};
int main() {
Animal* pet = new Dog;
delete pet;
return 0;
}
/home/abDVbj/cc8ghrZk.o: In function `Dog::~Dog()':
prog.cpp:(.text._ZN3DogD2Ev[_ZN3DogD5Ev]+0xb): undefined reference to `Animal::~Animal()'
/home/abDVbj/cc8ghrZk.o: In function `Dog::~Dog()':
prog.cpp:(.text._ZN3DogD0Ev[_ZN3DogD0Ev]+0x12): undefined reference to `Animal::~Animal()'
it will , destructor is not really destroy the object you created , it is called before the object being destroied, if you have not new something in constructor , there is no need for you to delete it.
I try to finger out a sample to prove
when using string(with a pointer member) object as member variable, its destructor will be called, even we do nothing in the class's destructor
so I tried to used a user-defined String as object, so it is easy for us to write some log in the destructor.
it outputs:
constructor is called
constructor is called
constructor is called
operator constructor is called
destructor is called
operator constructor is called
destructor is called
virtual ~Dog()
virtual ~Animal()
destructor is called
it show is when virtual ~Animal() is called , the string object'destructor in the Animal class is called.
we can change the string object to string*(using new in construtor) while still doing nothing in the destructor , and we will see the string's destructor is not called
#include <iostream>
#include <string.h>
using namespace std;
class String{
public:
String(const char *str = NULL);
String(const String &str);
~String();
String operator+(const String & str);
String & operator=(const String &str);
bool operator==(const String &str);
int Length();
friend ostream & operator<<(ostream &o,const String &str);
String SubStr(int start, int end);
private:
char * charArray;
};
String::String(const char *str)
{
if(str == NULL){
charArray=new char[1];
charArray[0]='\0';
}else{
charArray=new char[strlen(str)+1];
strcpy(charArray,str);
}
std::cout<< "constructor is called" << std::endl;
}
String::String(const String &str)
{
std::cout<< "constructor is called" << std::endl;
charArray = new char[strlen(str.charArray)+1];
strcpy(charArray,str.charArray);
}
String::~String()
{
std::cout<< "destructor is called" << std::endl;
delete [] charArray;
}
String String::operator+(const String &str)
{
String res;
delete [] res.charArray;
res.charArray = new char[strlen(charArray)+strlen(str.charArray)+1];
strcpy(res.charArray,charArray);
strcpy(res.charArray+strlen(charArray),str.charArray);
return res;
}
String & String::operator=(const String &str)
{
if(charArray == str.charArray)
return *this;
delete [] charArray;
charArray = new char[strlen(str.charArray)+1];
strcpy(charArray,str.charArray);
std::cout<< "operator constructor is called" << std::endl;
return *this;
}
bool String::operator==(const String &str)
{
return strcmp(charArray,str.charArray) == 0;
}
int String::Length()
{
return strlen(charArray);
}
ostream & operator<<(ostream &o, const String &str)
{
o<<str.charArray;
return o;
}
String String::SubStr(int start, int end)
{
String res;
delete [] res.charArray;
res.charArray = new char[end-start+1];
for(int i=0; i+start<end; i++){
res.charArray[i]=charArray[start+i];
}
res.charArray[end-start] = '\0';
return res;
}
class Animal {
public:
Animal();
virtual ~Animal()=0;
Animal(String name, int age);
public:
int _age;
String _name;
};
Animal::~Animal(){
std::cout << "Animal::~Animal()" << std::endl;
}
Animal::Animal(String name, int age)
{
this->_name = name;
this->_age = age;
}
class Dog :public Animal
{
public:
virtual ~Dog() {
std::cout << "virtual ~Dog()" << std::endl;
};
Dog(String name, int age):Animal(name,age)
{
this->_name = name;
this->_age = age;
}
};
int main(){
Animal* p = new Dog( String("dog"),1);
delete p;
return 0;
}
Related
I am having some trouble with an unexpected output in the following simple code. The output works fine with the base class but I run into trouble with the derived class for some reason.
#include <iostream>
#include <string>
using namespace std;
class vehicle {
public:
string* name;
vehicle() {}
vehicle(const string& inputName) {name = new string(inputName);} //constructor
virtual ~vehicle() {delete name; name = nullptr;} // always make base class destructor virtual
//vehicle(const vehicle& rhs) {*this = rhs; cout << "copy called" << endl;} //copy constructor
vehicle& operator=(const vehicle& rhs) {
cout << "assignment called" << endl;
if(this == &rhs){
return *this;
}
name = new string(*rhs.name);
return *this;
} //assignment operator
virtual string& getName() const {return *name; cout << "base" << endl;} //mark function const if we are not going to make any changes to the object
};
class car : public vehicle {
string *title = new string;
public:
car() : vehicle() {}
car(const string& inputName) : vehicle(inputName) {*title = inputName;}
virtual ~car() {}
virtual string& getName() const {string temp = *title; return temp; cout << "derived" << endl;}
};
int main() {
car test("honda");
string temp;
temp = test.getName();
cout << temp;
return 0;
}
I am intending to get the following output:
honda
But am getting:
~weird square boxes~
Edit:
What i'm really trying to accomplish is something like the following in the derived class:
virtual string& getName() const {return "Car: " + *name;}
Before I get enflamed for using the heap for the string, please know that I am only experimenting here. It is my understanding that this should, in theory, work.
This function
virtual string& getName() const {string temp = *title; return temp; cout << "derived" << endl;}
invokes undefined behavior because it returns a reference to a local object temp that will not be alive after exiting the function.
You could define the function like
virtual const string& getName() const {return *name;}
and
const string& getName() const override { return *title;}
And the statements after return statements do not have an effect.
Also other your code has drawbacks. For example the copy assignment operator produces a memory leak.
Or you need explicitly to define the destructor for the class car.
Pay attention to that there is no sense to declare data members name and title as pointers to objects of the type std::string. Instead declare data members of the type std::string.
I have a simple program where I am trying to do operator overloading for new and delete.
Just for trying, I did operator overloading for new and delete in global scope apart from class scope.
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
using namespace std;
void * operator new(size_t size)
{
cout<<"\n\nGlobal scope new:\n";
void * ptr = malloc(size);
return ptr;
}
void operator delete(void *ptr)
{
cout<<"\n\nGlobal scope delete:\n";
free(ptr);
}
class test
{
public:
int age;
string name;
test(string str, int a)
{
age = a;
name = str;
}
void display();
};
void test::display()
{
cout<<"\n\nname is:-"<<name<<" and age is :- "<<age<<endl;
}
int main()
{
test *t = new test("sanjeev",29);
if(t!=NULL)
cout<<"\n\nMemory allocated:"<<endl;
t->display();
delete t;
}
Now on executing this program I am seeing that new is called 3 times and delete is called 3 times.
If I declare new and delete operator overloading inside class only one time call to new and delete is happening.
What is the reason behind this flow?
std::string ultimately uses the global operator new. You're creating two std::strings.
You should override operator new in your base class if you don't want new to be called multiple times in this case:
class CBaseTest
{
public:
void *operator new(const size_t allocation_size)
{
cout<<"\n\nMy new invoked:\n";
return ::malloc(allocation_size);
}
void operator delete(void *block_of_memory)
{
cout<<"\n\nMy delete invoked:\n";
::free(block_of_memory);
}
};
class test : public CBaseTest
{
public:
int age;
string name;
test(string str, int a)
{
age = a;
name = str;
}
void display();
};
void test::display()
{
cout << "\n\nname is:-" << name << " and age is :- " << age << endl;
}
Here
test *t = new test("sanjeev", 29);
will invoke your new method.
Similarly,
delete t;
will invoke your delete method
Now, if you try to allocate memory using new for your class test or any classes derived from CBaseTest then your new will be called.
I was trying to revise my Object Oriented programming concepts. While going through this basic C++ example here, I saw that the this-> keyword has not been used when setting values for the member variables. I then modified this program to set use the this keyword. Surprisingly, both work (this and this).
#include <iostream> // for cout and cin
class Cat // begin declaration of the class
{
public: // begin public section
Cat(int initialAge); // constructor
Cat(const Cat& copy_from); //copy constructor
Cat& operator=(const Cat& copy_from); //copy assignment
~Cat(); // destructor
int GetAge() const; // accessor function
void SetAge(int age); // accessor function
void Meow();
private: // begin private section
int itsAge; // member variable
char * string;
};
// constructor of Cat,
Cat::Cat(int initialAge)
{
itsAge = initialAge;
string = new char[10]();
}
//copy constructor for making a new copy of a Cat
Cat::Cat(const Cat& copy_from) {
itsAge = copy_from.itsAge;
string = new char[10]();
std::copy(copy_from.string+0, copy_from.string+10, string);
}
//copy assignment for assigning a value from one Cat to another
Cat& Cat::operator=(const Cat& copy_from) {
itsAge = copy_from.itsAge;
std::copy(copy_from.string+0, copy_from.string+10, string);
}
Cat::~Cat() // destructor, just an example
{
delete[] string;
}
// GetAge, Public accessor function
// returns value of itsAge member
int Cat::GetAge() const
{
return itsAge;
}
// Definition of SetAge, public
// accessor function
void Cat::SetAge(int age)
{
// set member variable its age to
// value passed in by parameter age
itsAge = age;
}
// definition of Meow method
// returns: void
// parameters: None
// action: Prints "meow" to screen
void Cat::Meow()
{
cout << "Meow.\n";
}
// create a cat, set its age, have it
// meow, tell us its age, then meow again.
int main()
{
int Age;
cout<<"How old is Frisky? ";
cin>>Age;
Cat Frisky(Age);
Frisky.Meow();
cout << "Frisky is a cat who is " ;
cout << Frisky.GetAge() << " years old.\n";
Frisky.Meow();
Age++;
Frisky.SetAge(Age);
cout << "Now Frisky is " ;
cout << Frisky.GetAge() << " years old.\n";
return 0;
}
So my question is, should we, or shouldn't we use this keyword in this context (when setting the values of the member variables)? Thanks!
Edit: Or, is this a personal preference as mentioned here?
In the context of the example the keyword this is usually used for self-documentation to distinguish non-static members of the class from local variables.
Constructor:
// constructor of Cat,
Cat::Cat(int initialAge)
{
itsAge = initialAge;
string = new char[10]();
}
You should write this as:
// constructor of Cat,
Cat::Cat(int itsAge)
: itsAge(itsAge),
string(new char[10])
{
}
Copy constructor:
//copy constructor for making a new copy of a Cat
Cat::Cat(const Cat& copy_from) {
itsAge = copy_from.itsAge;
string = new char[10]();
std::copy(copy_from.string+0, copy_from.string+10, string);
}
You should write this as:
Cat::Cat(const Cat& copy_from)
: itsAge(copy_from.itsAge),
string(new char[10])
{
std::copy(copy_from.string, copy_from.string+sizeof string, string);
}
Copy assignment:
//copy assignment for assigning a value from one Cat to another
Cat& Cat::operator=(const Cat& copy_from) {
itsAge = copy_from.itsAge;
std::copy(copy_from.string+0, copy_from.string+10, string);
}
You should write this as:
Cat& Cat::operator=(const Cat& copy_from)
{
this->itsAge = copy_from.itsAge;
std::copy(copy_from.string, copy_from.string + sizeof string, string);
}
Mutator:
// Definition of SetAge, public
// accessor function
void Cat::SetAge(int age)
{
// set member variable its age to
// value passed in by parameter age
itsAge = age;
}
You should write this as:
void Cat::SetAge(int itsAge)
{
this->itsAge = itsAgege;
}
In other words:
use member initialization lists wherever possible
use the same name for arguments as for the members they are going into, to economize on identifiers and increase clarity
use this-> where necessary to eliminate ambiguity or error.
I have looked all around and can't find the answer to my question anywhere. I am trying to use a copy constructor of a derived class from a pointer array of base classes. The only thing I have learned is I should probably use dynamic_cast but cant get that working.
This is the important parts of my code so far (original is way to big since I have 16 different files but this should be enough).
EDIT: The error I receive doing it this way is |26|error: cannot dynamic_cast '& properties[0]' (of type 'class Property**') to type 'class Commercial*' (source is not a pointer to class)|
#include "rentals.h"
#include "commercial.h"
#include "sales.h"
#include "comSales.h"
#include "resSales.h"
#include "resRentals.h"
#include "comRentals.h"
const int MAX_PROPERTIES = 5;
int main(void) {
int i;
Property *properties[MAX_PROPERTIES];
properties[0] = new Commercial("Notting Hill McDonalds", "4 Gardiner Road",
"Notting Hill", 5000, "Li3000");
properties[1] = new ResRentals("Janet Dalgleish", "30 Firhill Court",
"Mary Hill", 4000, 500.00, 300.00, 4);
properties[2] = new Commercial(dynamic_cast<Commercial*>(properties[0])); // <-- the copy constructor I can not get to work.
delete[] properties;
return 0;
}
commercial.cpp file
#include "property_a.h"
#include "commercial.h"
Commercial::Commercial() : Property() {
owner = "NULL";
address = "NULL";
suburb = "NULL";
postcode = 0;
license = "NULL";
}
Commercial::Commercial(string theOwner, string theAddress,
string theSuburb, int thepostCode,
string theLicense): Property(theOwner, theAddress,
theSuburb, thepostCode), license(theLicense) {}
Commercial::~Commercial() {}
Commercial::Commercial(const Commercial& orig) : Property(orig),
license(orig.getLicense()) {}
void Commercial::print() {
cout << getOwner() << endl;
cout << getAddress() << endl;
cout << getSuburb() << endl;
cout << getPostcode() << endl;
cout << getLicense() << endl;
}
commercial.h file
#ifndef __COMMERCIAL_H__
#define __COMMERCIAL_H__
#include "property_a.h"
class Commercial : public virtual Property
{
protected:
string license;
public:
Commercial();
Commercial(string theOwner, string theAddress, string theSuburb,
int thepostCode, string theLicense);
~Commercial() ;
Commercial(const Commercial& orig);
void input() ; // Data input for a Shop object
void print() ; // Data output for a Shop object
string getLicense() const {return license;}; //Note the use of const
void setLicense(string theLicense) {license = theLicense;};
};
property_a.cpp file
#include "property_a.h"
Property::Property(){
owner = "NULL";
address = "NULL";
suburb = "NULL";
postcode = 0;
}
Property::Property(string theOwner, string theAddress,
string theSuburb, int thepostCode):
owner(theOwner), address(theAddress),
suburb(theSuburb), postcode(thepostCode){}
Property::~Property() {}
Property::Property(const Property& orig) :
owner(orig.getOwner()), address(orig.getAddress()),
suburb(orig.getSuburb()), postcode(getPostcode()) {}
property_a.h file
#ifndef __PROPERTY_A_H__
#define __PROPERTY_A_H__
/*TODO REQUIRED HEADER FILES AND NAMESPACES*/
#include <string>
#include "utility1.h"
class Property
{
protected:
string owner;
string address;
string suburb;
int postcode;
public:
Property();
Property(string theOwner, string theAddress, string theSuburb, int thepostCode);
virtual ~Property();
Property(const Property& orig);
virtual void input() ; // Data input for a Property object
virtual void print() ; // Data output for a Property object
string getOwner() const {return owner;}; //Note the use of const
string getAddress() const {return address;};
string getSuburb() const {return suburb;};
int getPostcode() const {return postcode;};
void setOwner(string newOwner) {owner = newOwner;};
void setAddress(string newAddress) {address = newAddress;};
void setSuburb( string newSuburb) {suburb = newSuburb;};
void setPostcode(int newPostcode) {postcode = newPostcode;};
};
#endif
I hope this is enough details
properties[2] = new Commercial(dynamic_cast(properties[0])); // <-- the copy constructor I can not get to work.
This is casting properties[0] to Commercial*. But this isn't the signature of your copy constructor. Therefore, you need new Commercial(*dynamic_cast<Commercial*>(properties[0]));.
In this example you could use static_cast<Commercial&>(*properties[0]) since you know properties[0] is a Commercial type.
However, in general if you're using dynamic_cast it probably means you're not sure what the derived type is and you would need to check for NULL (i.e., the cast failed) before dereferencing.
Alternative
You could consider a polymorphic API to take care of this for you.
class Base
{
public:
virtual ~Base() = default;
Base* clone() const = 0;
};
class D1 : public Base
{
public:
virtual ~D1() override = default;
D1* clone() const { return new D1(*this); }
};
class D2 : public Base
{
public:
virtual ~D2() override = default;
D2* clone() const { return new D2(*this); }
};
int main()
{
std::unique_ptr<Base> b1(new D2());
std::unique_ptr<Base> b2(b1->clone());
return 0;
}
It would be nice to see the errors but it looks like you aren't calling the copy constructor at all:
new Commercial(dynamic_cast<Commercial*>(properties[0]));
is like calling
Commercial(Commercial * other);
so you need
new Commercial(*dynamic_cast<Commercial*>(properties[0]));
I learned that one of the motivation for copy constructor using is to avoid of the follow crash in the program -
#include <iostream>
using namespace std;
class Employee {
public:
Employee(int ID,char const * name){...};
~Employee(){...};
// Methods
void Print();
private:
// members
int m_ID;
char* m_name;
};
void MyFunc(Employee emp) {
cout << "in MyFunc \n ";
}
int main() {
Employee One(1,"Garen Torosian");
// calling copy constructor
MyFunc(One);
cout << "In the end of main \n";
// Here the program crashes!
return 0;
}
as you can see the program should be crash before the return 0; , but when I run that program it works fine and terminated ok , why ?
Edit : In this case the program indeed crash -
// Employee.h
#include <iostream>
using namespace std;
class Employee {
public:
Employee(int ID,
const char* name);
~Employee();
// Methods
void Print();
private:
// members
int m_ID;
char* m_name;
};
// Employee.cpp
#include "Employee.h“
Employee::Employee(int iID, const char *name){ // Ctor
cout << "Constructor called" << endl;
m_ID = iID;
m_name = new char [strlen(name) +1];
strcpy(m_name, name);
Print();
}
void Employee::Print() { // Print
cout << "ID: " << m_ID << ",Name:” << m_name
<< " ,Address(pointer):0x" << hex << (int) m_name<< endl;
}
Employee::~Employee() { // Dtor
cout << "Destructor called"<<endl;
Print();
delete [] m_name;
m_name=NULL;
}
void MyFunc(Employee emp) {
cout << "in MyFunc \n ";
}
int main()
{
Employee One(1,"Eli Rachamim");
// calling copy constructor
MyFunc(One);
cout<< "In the end of main \n“;
// Here the program crashes!
return 0;
}
If you d-tor is like
~Employee(){ delete[] name; }
and you alloc memory for your char* pointer, and you have no copy c-tor, than copy c-tor generated by compiler, that do memberwise-copy, will be called when you copy object. So, there will be double-free, that in most cases give you memory dump (in real calling destructor to already destructed object is UB and calling delete[] on already deleted object is also UB). But if you don't work with memory - copy c-tor, generated by compiler works well.
EDIT.
So, your second example demonstrates call of d-tor to allready destructed object and also double-free.
Why do you think it should crash?
C++ has the unfortunate feature of supplying an automatically-generated copy-constructor if you don't provide one, and your MyFunc() doesn't really do anything that would get screwed by that auto-generated copy.