When I talk about exception handling for classes, I am not really sure if I understood the exceptions really well. One grey area which I can find is to handle exceptions for class hierarchies. For e.g.
#include<iostream>
class B {
public:
B() {
std::cout << "B ctor" << std::endl;
}
~B() {
std::cout << "B dtor" << std::endl;
}
};
class D : public B {
public:
D() {
std::cout << "D ctor" << std::endl;
}
~D() {
std::cout << "D dtor" << std::endl;
}
};
int main() {
try {
D d;
throw d;
} catch (D &d) {
std::cout << "Derived caught" << std::endl;
} catch (B &b) {
std::cout << "Base caught" << std::endl;
}
}
This actually prints :
B ctor
D ctor
D dtor
B dtor
Derived caught
D dtor
B dtor
D dtor
B dtor
I did not understand why and what should I do to overcome this in case it is not encouraged.
Related
Why does this give this error -
'void D::func(const D &)': cannot convert argument 1 from 'const C' to 'const D &'
How to correct this, I want to call Base's func from Derived's func but note func is a friend function?
class C
{
public:
C()
{
cout << "in C ctor" << endl;
}
friend void func(const C& abc1)
{
cout << "in C's func" << endl;
}
};
class D : public C
{
public:
D()
{
cout << "in D ctor" << endl;
}
void func(const D& abc)
{
func(static_cast<const C&>(abc));
cout << "in D's func" << endl;
}
};
int main()
{
D d;
d.func(d);
}
why does this similar e.g. work though -
https://ideone.com/eNmvng
I'm not sure what that syntaxis does with function visibility, but this works:
class C
{
public:
C()
{
cout << "in C ctor" << endl;
}
friend void func(const C& abc1);
};
void func(const C& abc1)
{
cout << "in C's func" << endl;
}
class D : public C
{
public:
D()
{
cout << "in D ctor" << endl;
}
void func(const D& abc)
{
::func(abc);
cout << "in D's func" << endl;
}
};
int main()
{
D d;
d.func(d);
}
Just for completeness sake, this works too:
class C
{
public:
C()
{
cout << "in C ctor" << endl;
}
friend void func(const C& abc1)
{
cout << "in C's func" << endl;
}
};
// Make function visible in global scope
void func(const C& abc1);
class D : public C
{
public:
D()
{
cout << "in D ctor" << endl;
}
void func(const D& abc)
{
::func(abc);
cout << "in D's func" << endl;
}
};
int main()
{
D d;
d.func(d);
}
I wrote this code to learn the shared_ptr object creation inside my own class.
Why is A object shared_ptr destroyed even before A's print (obj->print() inside B's print) is called?
#include <iostream>
#include <memory>
using namespace std;
class A {
private: string str;
public:
A(string s){
str = s;
cout<<"class A: "<< str << endl;}
~A() { cout << "destroying A: " << str << endl;}
void print() { cout << "A print called" << endl;}
};
class B {
private: shared_ptr<A> obj;
public:
B() { cout << "default construct called" << endl;}
B(string s) {
cout << "shared_ptr creation" <<endl;
shared_ptr<A> obj = make_shared<A>(s);
cout << "shared_ptr creation done" <<endl;
}
~B() { cout<<"destroying B" << endl;}
void print() { obj->print();cout << "B print called" << endl;}
};
void func( B i) { i.print();}
int main()
{
{
B b("hello world");
func(b);
}
cout << "in main" << endl;
return 0;
}
output:
shared_ptr creation
class A: hello world
shared_ptr creation done
destroying A: hello world
A print called
B print called
destroying B
destroying B
in main
In B::B(string), shared_ptr<A> obj = make_shared<A>(s); is constructing a local object which gets destroyed immediately when the constructor ends; it has nothing to do with the data member obj, which points to nothing as the result.
I think you want:
B(string s) {
cout << "shared_ptr creation" <<endl;
obj = make_shared<A>(s); // assignment to the data member obj
cout << "shared_ptr creation done" <<endl;
}
Or initialize it in member initializer list.
B(string s) : obj(make_shared<A>(s)) { // initialize the data member obj
cout << "shared_ptr creation done" <<endl;
}
i have troubles with some methods after inherit.
It's hard (for me) to say where exactly problem is but i will try to expose this by example.
Minimal code:
#include <iostream>
class A
{
public:
A() {};
A(int x):val(x)
{
std::cout << "A constructor work" << std::endl;
}
int get()
{
std::cout << "Get A work" << std::endl;
return val;
}
protected:
int val;
};
class B: protected A
{
public:
B(int x) :A(x)
{
std::cout << "B constructor work" << std::endl;
test();
}
int get()
{
std::cout << "Get B work" << std::endl;
return A::get();
}
protected:
void test()
{
if (A::val == 0)
{
std::cout << "Test B work" << std::endl;
A::val = 1;
}
}
};
class C : protected A
{
public:
C() {};
C(int x) :A(x)
{
std::cout << "C constructor work" << std::endl;
test();
}
int get()
{
std::cout << "Get C work" << std::endl;
return A::get();
}
protected:
void test()
{
std::cout << "Test C work" << std::endl;
if (A::val != 0)
{
A::val += 2;
}
}
};
class D : private B, private C
{
public:
D(int x):B(x)
{
std::cout << "D constructor work" << std::endl;
C::test();
}
int get()
{
std::cout << "Get D work" << std::endl;
return B::get();
}
};
int main()
{
D d(0);
std::cout << d.get() << std::endl;
}
Output:
**A constructor work
B constructor work
Test B work
D constructor work
Test C work
Test C extra work
Get D work
Get B work
Get A work
1**
I expect val = 3 in the end, but it dont work like that.
I would be particularly grateful for your detailed reply.
Your class D contains two A objects - the one inherited by B and the one inherited by C
When you call C::test() you change the A object in C.
When you call D::get() - which calls B::get() - you inspect the value of the A object in B.
One way to get around this is by means of virtual inheritance. That is not something you want to mess with until you understand how multiple inheritance works, though.
I have an explicit function that takes a reference to the base type of a class. What is the proper way to pass that in?
I am currently doing a static cast:
#include <iostream>
using namespace std;
struct Base
{
Base() { cout << "Base Constructor" << endl; }
Base(Base const& c) { cout << "Base-Base Constructor" << endl; }
};
struct Derived : public Base
{
Derived() { cout << "Derived Constructor" << endl; }
explicit Derived(Base const& c) { cout << "Derived-Base Constructor" << endl; }
Derived(Derived const& c) { cout << "Derived-Derived Constructor" << endl; }
};
int main()
{
Base B;
cout << "\n";
Derived D;
cout << "\n";
Base* test1 = new Derived(D);
cout << "\n";
Base* test3 = new Derived(static_cast<Base>(D));
cout << "\n";
Base* test2 = new Derived(B);
cout << "\n";
return 0;
}
but that calls the copy constructor of the base class.
I could pass *static_cast<Base*>(&D), but that seems a bit hackish. I feel like I am just overlooking a simple way to do this. Thanks.
Use this:
static_cast<Base&>(D)
Or this:
static_cast<const Base&>(D)
I have read several articles here and else where that it is OK to throw exception from constructor. However, I have noticed that it doesn't call destructor of base class or its data members if an exception is thrown from the constructor. Consider the following example:
#include <iostream>
using namespace std;
struct C
{
C() { cout << __FUNCTION__ << endl; }
~C() { cout << __FUNCTION__ << endl; }
};
struct E: public C
{
C c;
E() { cout << __FUNCTION__ << endl; throw 4; }
~E() { cout << __FUNCTION__ << endl; }
};
int main()
{
E e;
}
$ g++ test.cpp; ./a.exe
C
C
E
terminate called after throwing an instance of 'int'
Aborted (core dumped)
In this case, E's constructor throws an exception but C's destructor as a data member or as a base class is not called. Now if C's destructor performs some cleanup operation like closing files/sockets and deleting heap allocations, this can cause problems.
So my question is why and when is it OK to throw exceptions from constructors.
If you catch the error, the destructor will be run. When an uncaught exception is thrown in C++, the runtime calls std::terminate. By default, std::terminate calls std::abort which specifically does not call destructors on the way out.
With this version:
#include <iostream>
using namespace std;
struct C
{
C() { cout << __FUNCTION__ << endl; }
~C() { cout << __FUNCTION__ << endl; }
};
struct E: public C
{
C c;
E() { cout << __FUNCTION__ << endl; throw 4; }
~E() { cout << __FUNCTION__ << endl; }
};
int main()
{
try {
E e;
} catch(...) {
}
return 0;
}
I get output:
C
C
E
~C
~C
I have noticed that it doesn't call destructor of base class or its data members if an exception is thrown from the constructor
Yes, it does.
However, since you don't catch that exception in the entire program, the program is immediately terminated.
If you were to catch the exception somewhere higher up the call stack, then the destructors of base class and members would be invoked as expected.
You don't handle the "exception".
> cat test.cpp
#include <iostream>
using namespace std;
struct C
{
C() { cout << __FUNCTION__ << endl; }
~C() { cout << __FUNCTION__ << endl; }
};
struct E: public C
{
C c;
E() { cout << __FUNCTION__ << endl; throw 4; }
~E() { cout << __FUNCTION__ << endl; }
};
int main()
{
try
{
E e;
}
catch (int i)
{
std::cerr << "Handled " << i << std::endl;
}
}
Build and run..
> make test
make: `test' is up to date.
> ./test
C
C
E
~C
~C
Handled 4
>
Both Cs destructed and a perfectly normal termination.
1) E's constructor catched the exception and ran completly.
Therefore, its object is created and the distructor is
invoked.
struct C
{
C() {cout <<__FUNCTION__<< endl;}
~C() {cout <<__FUNCTION__<< endl;}
};
struct E: public C
{
C c;
E() {
try {
cout <<__FUNCTION__<< endl;
throw 4;
}
catch(int i) {
cerr<<"int "<<i<<" is catched by "<<__FUNCTION__<<endl;
}
}
~E() {cout << __FUNCTION__ << endl;}
void print(){
cout<<"obj of class E is created"<<endl;
}
};
int main()
{
try {
E e;
e.print();
}
catch(int i) {
cerr<<"int "<<i<<" catched by "<<__FUNCTION__<<" function"<<endl;
}
return 0;
}
/*
Results:
C::C
C::C
E::E
int 4 is catched by E::E
obj of class E is created
E::~E
C::~C
C::~C
*/
2) E's constructor didn’t catch the exception and ran incompletly.
In result, its object is not created. Therefore, its distructor
is not invoked.
struct C
{
C() {cout <<__FUNCTION__<< endl;}
~C() {cout <<__FUNCTION__<< endl;}
};
struct E: public C
{
C c;
E() {
try {
cout <<__FUNCTION__<< endl;
throw 4;
}
catch(float i) {
cerr<<"int "<<i<<" is catched by "<<__FUNCTION__<<endl;
}
}
~E() {cout << __FUNCTION__ << endl;}
void print(){
cout<<"obj of class E is created"<<endl;
}
};
int main()
{
try {
E e;
e.print();
}
catch(int i) {
cerr<<"int "<<i<<" catched by "<<__FUNCTION__<<" function"<<endl;
}
return 0;
}
/*
Results:
C::C
C::C
E::E
C::~C
C::~C
int 4 catched by main function
*/