0

I'm not sure if "throw errors to other classes" is correct to describe my question.

The example is as follows.There're two classes:

  • A is a class that being used as a directory, just like a directory in the system. It has two private values call file and directory. It has a public function called mkdir, which will make a directory.It'll throw errors if dirname(what to mkdir) already exists.
  • B is a class that being used as command, which also has a function called mkdir function. mkdir in B accepts two parameters: pointer to A and dirname.

How should I throw an error in A and then catch it in B ? I searched some websites but they only had instructions for throw in functions. Thanks!

Update 1:

At first I tried to write a bool function called isExist in A, and use it in B before mkdir. If isExist = true, throw errors(..);

What I'm trying to do here is to regard A as an object, and itself should throw an error if possible.

code:

class A{

private:
    file f;
    directory d;
public:
    void mkdir(const string& dirname);
}

class B {
private:
       shared_ptr<A> p;
public:
       void mkdir(shared_ptr<A>, const string&);
}

Update 2:

Ty guys for your answers, I'm much clearer right now. Here're a few useful comments provided @ molbdnilo by in case someone like me are also confused about exceptions.

I'll try to be clearer: If B::mkdir calls A::mkdir, it can catch exceptions that A::mkdir throws. If something else calls A::mkdir, B::mkdir can't notice anything at all. Exceptions have absolutely nothing to do with classes, they only concern the execution of functions. Exceptions work the same regardless of whether the function is a member of a class or not.

Besides, @el.pescado also lists a nice answer.

Kevin217
  • 724
  • 1
  • 10
  • 20
  • @DieterLücking should I write a bool function in `A` to check if exists, and uses it in `B` before `mkdir`? – Kevin217 Jan 26 '16 at 19:41
  • 1
    Probably we will understand the question better if you would post a code skeleton. – xtofl Jan 26 '16 at 19:42
  • 1
    @Kevin217 What you're suggesting is a race condition. – Ami Tavory Jan 26 '16 at 19:42
  • @xtofl please see the update – Kevin217 Jan 26 '16 at 19:48
  • @AmiTavory do you mean the program doesn't know which error to throw first? – Kevin217 Jan 26 '16 at 19:48
  • The fact that you're using classes is actually irrelevant here. – user253751 Jan 26 '16 at 19:49
  • @immibis really? irrelevant? – Kevin217 Jan 26 '16 at 19:49
  • Can you elaborate by what you mean by "throw an exception to class A?" Is the goal to have the A object deal with any errors that are generated? – templatetypedef Jan 26 '16 at 19:51
  • 1
    @Kevin217 Yes. What you're asking is how *`A::mkdir`* and catch it in *`B::mkdir`*. Those are both just functions. Member functions sure, but that's irrelevant. When you throw an exception it will propagate to the caller, and that function's caller, and so on, until one catches it. – user253751 Jan 26 '16 at 19:52
  • @templatetypedef Yes! that's what I mean! – Kevin217 Jan 26 '16 at 19:52
  • @Kevin217 You can check a directory exists or not, decide whatever you want based on that, and in the following command it will have changed completely (some other process created/deleted it). This is called a race condition. – Ami Tavory Jan 26 '16 at 19:53
  • @immibis so what you're saying here is i cannot let `B` handler error in `A`? – Kevin217 Jan 26 '16 at 19:55
  • 3
    "A is a class called directory". What could that possibly mean? If A is a class, it's a "class called A". – n. m. could be an AI Jan 26 '16 at 19:59
  • 1
    I don't know what you mean by "B is an upper class of A". Do you mean that B inherits from A? – Carlton Jan 26 '16 at 20:02
  • @Carlton No. I just mean B has a pointer that points to A – Kevin217 Jan 26 '16 at 20:04
  • 1
    The function `B::mkdir` can catch exceptions that occur when it calls the function `A::mkdir`. (Again: that these are member functions are completely irrelevant.) – molbdnilo Jan 26 '16 at 20:05
  • 1
    You cannot throw exceptions from a class. You can throw exceptions from member functions, but it is no different from throwing from an ordinary function or just any other function. – el.pescado - нет войне Jan 26 '16 at 20:05
  • 1
    @Kevin217That's not an "upper class", that's a "member variable". [A good book](http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list) would help you improve your vocabulary, and also hopefully clarify some things about classes, instances, and member functions. – molbdnilo Jan 26 '16 at 20:08
  • @molbdnilo confused. Do you mean that I can use B::mkdir to catch exceptions from A::mkdir. But it's a bad idea because A::mkdir and B::mkdir are member function, and making it irrelevant? – Kevin217 Jan 26 '16 at 20:09
  • @molbdnilo ty but it's just translating issues – Kevin217 Jan 26 '16 at 20:10
  • Why does B have a pointer to an A, but B::mkdir also accepts a pointer to an A? That feels weird. Also, I get the feeling that you misunderstand what the word "irrelevant" means. – Sebastian Redl Jan 26 '16 at 20:18
  • 2
    @Kevin217 I'll try to be clearer: If `B::mkdir` calls `A::mkdir`, it can catch exceptions that `A::mkdir` throws. If *something else* calls `A::mkdir`, `B::mkdir` can't notice anything at all. Exceptions have absolutely nothing to do with classes, they only concern the execution of functions. Exceptions work the same regardless of whether the function is a member of a class or not. – molbdnilo Jan 26 '16 at 20:21
  • @SebastianRedl regardless of the pointer, can you simply explain what does "irrelevant" mean here? – Kevin217 Jan 26 '16 at 20:21
  • @molbdnilo ty! that's very clear. – Kevin217 Jan 26 '16 at 20:25
  • 1
    1. "A is a class that being used as a directory". Why not call it `class Directory` then? 2. Are you sure a command should hold a pointer to a directory? Wouldn't the pointer passed to `mkdir` be enough? – n. m. could be an AI Jan 26 '16 at 20:27
  • @n.m. 1. By writing so, I can make the whole question much shorter. By writing so, I can directly get the answer about what i'm confused. ty all the way – Kevin217 Jan 26 '16 at 20:32

3 Answers3

3

If I understand what you want to do, you can catch an exception in one class's member function, then pass it off to a member function of another class. My example below uses free functions instead of member functions, but the principle is the same:

#include <iostream>
#include <stdexcept>

using namespace std;

void HandleException(exception& exc) {
    cout << "Exception: \"" << exc.what() << "\" has been handled." << endl;
}

void DoSomethingRisky(double x) {
    if (x == 0)
        throw std::runtime_error("x must be non-zero");
    else
        cout << x << endl;
}

int main() {

    try {DoSomethingRisky(0);}
    catch (exception& exc) {
        HandleException(exc);
    }

    return 0;
}

Edit: below is an example using member functions in the style of the example from your original question:

#include <iostream>
#include <stdexcept>

using namespace std;

struct A {
    void HandleException(exception& exc) {
        cout << "Exception \"" << exc.what() << "\" has been handled." << endl;
    }
};

struct B {

    B(A* a): a_ptr(a) {}

    void DoSomethingRisky(double x) {
        try {
            if (x == 0)
                throw runtime_error("x must be non-zero");
            else
                cout << x << endl;
        }
        catch (exception& exc) {
            a_ptr->HandleException(exc);
        }
    }

    A* a_ptr;

};

int main() {

    A a;
    B b(&a);
    b.DoSomethingRisky(0);

    return 0;
}
Carlton
  • 4,217
  • 2
  • 24
  • 40
2

If B inherits from A, and A is an abstract class never intended to be instantiated alone, you can define the implementation in the subclass, but call the "true" method in the superclass by obscuring the implementation and still handling errors in the superclass, like so (untested beyond compilation):

#include <exception>

using namespace std;

class A {
public:
  void myfunc();

protected:
  virtual void myfunc_impl() = 0;
};

class B : public A {

protected:
  void myfunc_impl() override {
    // do stuff
    throw std::exception();
  }
};

void A::myfunc() {
  try {
    myfunc_impl();
  } catch(std::exception &e) {
    // handle exception
  }
}

This is called the non virtual interface idiom (credit: @xtofl for clarifying the name!)

Community
  • 1
  • 1
Aaron Burke
  • 486
  • 3
  • 12
2

I searched some websites but they only had instructions for throw in functions.

That's because throwing exceptions from methods (a.k.a. member functions) is no different from throwing exceptions from regular functions:

// some system headers...
#include <sys/stat.h>
#include <sys/errno.h>
#include <stdio.h>

void A::mkdir(const string &dirname)
{
    int code = ::mkdir(dirname.c_str(), 0755); // calling system mkdir() function
    if (code != 0) {
        // creating directory failed

        char *message = strerror(errno); // get system errror message
        throw std::runtime_error(message); // throw exception as usual
    }
}

void B::mkdir(shared_ptr<A> a, const string &dirname)
{
    try { // call A::mkdir, any axecptions thrown there will propagate here
        a->mkdir(dirname);
    }
    catch (std::exception &e) { // catch exception as usual
        std::cout << "Creating directory failed: " << e.what() << std::endl;
    }
}