C++ 中的继承

发布于 2024-12-05 14:31:13 字数 2463 浏览 0 评论 0原文

编辑2:

这是我想做的事情的简单总结(我认为)我想根据运行时计算的条件动态创建全局实例。

如果您想查看示例代码,可以跳到 EDIT1,但此时,上面的粗体部分-text 可能是最容易理解的...

END EDIT 2.

我的问题是关于多态性和继承。具体来说,我想知道是否有一种方法可以从另一个类继承函数和指针。

我有一个名为 Globals 的类,其中包含指向其他类的对象的各种指针以及各种函数。我将编写一个简单的示例,而不是复制/粘贴代码:

(为了简单和清洁,我已删除标头防护)

以下是我的 globals.h 和分别是 globals.cpp

// Example of globals.h
#include <iostream>
#include <cstdio>
using namespace std;

class Globals {
  public:
    Globals ();
    virtual ~Globals ();

    void function1(char*);
    void function2();

    class Input *input;
    class Error *error;

};

// Example of globals.cpp
#include "globals.h"
Globals::Globals()
{
    input = new Input();
    error = new Error();
}

void Globals::function1(char*nm)
{
    cout << nm << endl;
}

现在,在我的 Input 类的代码中,假设我想使用 function1(char*) 方法,如果不将对象传递给输入类?我的意思是,我目前的 Input 类被传递了一个 *globals 对象,所以我可以像这样调用该函数: globals-> ;函数2();。但如果我在不同的类中有很多函数,这可能会变得非常混乱。此外,有没有办法可以使用 Error 指针来指向 Globals 中初始化的对象?如果 Error 有一个名为 error_func() 的函数,我怎样才能像这样调用它: error->error_func() from在我的 Input 函数中?

谢谢,如果我的问题太令人困惑,我深表歉意。如果需要,我很乐意详细说明。

Amit

编辑 1:添加了一个简化的代码,以更清晰的方式呈现我想要做的事情

// Example of globals.h
#include <iostream>
#include <cstdio>
#include "input.h"
#include "error.h"

using namespace std;


class Globals {
  public:
    Globals ();
    virtual ~Globals ();

    class Input *input;
    class Error *error;

};

// Example of globals.cpp
#include "globals.h"
Globals::Globals()
{
    input = new Input();
    error = new Error();
}

// Example of input.h
#include "globals.h"
class Input {
    public:
        Input();
        virtual ~Input();
}

// Example of input.cpp
#include "globals.h"
Input::Input()
{
    error->print("Hello\n"); // <-- THIS is really what I want to accomplish (without being sent a globals object and say globals->error->print();
}

// Example of error.h
#include "globals.h"
class Error {
    public:
        Error() { }
        virtual ~Error() { } 
        void print(char*);
}

// Example of error.cpp
#include "globals.h"
Error::print(char* nm)
{
    cout << nm << endl;
}

EDIT 2:

Here is a simple summary of what I want to do (I think):
I want to dynamically create global instances based on conditions that are calculated at run time.

You can skip to EDIT1 if you'd like to take a look at sample code, but at this point, the above bolded-text is probably the easiest to understand...

END EDIT 2.

My question is about polymorphism and inheritance. Specifically, I want to know if there is a way I could inherit functions and pointers from another class.

I have a class called Globals which contains various pointers to objects to other classes as well as various functions. Instead of copy/pasting code, I'll write up a simple example:

(I've removed header guards for simplicity and cleanliness)

The following is my globals.h and globals.cpp, respectively:

// Example of globals.h
#include <iostream>
#include <cstdio>
using namespace std;

class Globals {
  public:
    Globals ();
    virtual ~Globals ();

    void function1(char*);
    void function2();

    class Input *input;
    class Error *error;

};

// Example of globals.cpp
#include "globals.h"
Globals::Globals()
{
    input = new Input();
    error = new Error();
}

void Globals::function1(char*nm)
{
    cout << nm << endl;
}

Now, in my code for my Input class, say I want to use the function1(char*) method, would this be possible without passing an object to the Input class? What I mean by this is that I currently have my Input class being passed a *globals object, so then I could call the function like so: globals->function2();. But this can get very messy if I have a lot of functions within different classes. Additionally, is there a way I could use the Error pointer to object initialized in Globals? If Error had a function called error_func(), how could I be able to call it like so: error->error_func() from within my Input functions?

Thanks, and I apologize if I were too confusing in my question. I'll be happy to elaborate if needed.

Amit

EDIT 1: Added a simplified code to present what I want to do in a clearer way

// Example of globals.h
#include <iostream>
#include <cstdio>
#include "input.h"
#include "error.h"

using namespace std;


class Globals {
  public:
    Globals ();
    virtual ~Globals ();

    class Input *input;
    class Error *error;

};

// Example of globals.cpp
#include "globals.h"
Globals::Globals()
{
    input = new Input();
    error = new Error();
}

// Example of input.h
#include "globals.h"
class Input {
    public:
        Input();
        virtual ~Input();
}

// Example of input.cpp
#include "globals.h"
Input::Input()
{
    error->print("Hello\n"); // <-- THIS is really what I want to accomplish (without being sent a globals object and say globals->error->print();
}

// Example of error.h
#include "globals.h"
class Error {
    public:
        Error() { }
        virtual ~Error() { } 
        void print(char*);
}

// Example of error.cpp
#include "globals.h"
Error::print(char* nm)
{
    cout << nm << endl;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

为你鎻心 2024-12-12 14:31:13

如果我正确理解你的问题,函数会自动“继承”,至少出于你需要的目的。

例如,您的全局类有两个方法:function1(char*)function2()。如果你创建一个类:

class Descendent
    : public Global
{  };

int main()
{
    Global * global = new Global();
    Global * desc = new Descendant();
    char * str = "string";

    // These two will run the same function:
    global->function1(str);
    desc->function1(str);
}

为了防止这种情况(根据当前类型调用函数),你必须使用 virtual,例如:

class Global
{
    virtual void function1(char *);
};

class Descendant
{
    virtual void function1(char *);
};

int main()
{
    Global * global = new Global();
    Global * desc = new Descendant();
    char * str = "string";

    // These two will NOT run the same function:
    global->function1(str);
    desc->function1(str);
}

现在,我不完全确定,但是单例习惯用法可能在这里有用,具体取决于如何使用global 您的 Global 是。在这种情况下,您将拥有一个类似的全局变量:

class Global
{
    static Global * GetSingleton()
    {
        if (!Global::m_Instance) Global::m_Instance = new Global();
        return Global::m_Instance;
    }

    void function1(char *);

    static Global * m_Instance;
};


class Descendant
{
    void function1(char *)
    {
        Global * global = Global::GetGetSingleton();
        // ...
    }
};

有多种方法可以处理类之间需要的全局变量和函数。可能是其中之一,具体取决于您正在做什么。如果没有,我会尝试编辑并推荐一个可行的。

If I'm understanding your question right, functions are automatically "inherited", at least for the purposes you need.

For example, your global class has two methods, function1(char*) and function2(). If you make a class:

class Descendent
    : public Global
{  };

int main()
{
    Global * global = new Global();
    Global * desc = new Descendant();
    char * str = "string";

    // These two will run the same function:
    global->function1(str);
    desc->function1(str);
}

To prevent that (functions being called based on the current type), you must use virtual, like:

class Global
{
    virtual void function1(char *);
};

class Descendant
{
    virtual void function1(char *);
};

int main()
{
    Global * global = new Global();
    Global * desc = new Descendant();
    char * str = "string";

    // These two will NOT run the same function:
    global->function1(str);
    desc->function1(str);
}

Now, I'm not entirely sure, but the singleton idiom may be of use here, depending on just how global your Global is. In that case, you would have a global like:

class Global
{
    static Global * GetSingleton()
    {
        if (!Global::m_Instance) Global::m_Instance = new Global();
        return Global::m_Instance;
    }

    void function1(char *);

    static Global * m_Instance;
};


class Descendant
{
    void function1(char *)
    {
        Global * global = Global::GetGetSingleton();
        // ...
    }
};

There are a variety of ways to work with globals and functions being needed between classes. One of these may be it, depending on what exactly you're doing. If not, I'll try to edit and suggest one that does work.

雾里花 2024-12-12 14:31:13

我想象你有这样的情况:

struct A {
  void f();
};

struct B {
  void g();
};

struct C : virtual A, virtual B {
  C(A *ap, B *bp) 
    : A(ap), B(bp)  // This doesn't actually work -- theoretical
  {
  }

  void h() 
  { 
     f(); // calls A::f()
     g(); // calls B::g();
  }
};

通常,当你创建一个 C 时,你会创建新的 As 和 B,但你想重新使用现有的,但仍然将其视为继承,这样你就不会不必显式指定要调用哪个对象。

不幸的是,C++ 不支持这一点。有几个选项:

您可以创建延迟函数调用的代理类:

struct AProxy {
  AProxy(A *ap) : a(*ap) { }
  void f() { a.f(); }

  A &a;
};

struct BProxy {
  BProxy(B *bp) : b(*bp) { }
  void g() { b.g(); }

  B &b;
};

struct C : AProxy, BProxy {
  C(A *ap,B *bp) : AProxy(ap), BProxy(bp) { }

  void h()
  {
    f(); // calls AProxy::f() which calls a.f()
    g(); // calls BProxy::g() which calls b.g()
  }
};

如果您在许多不同的地方使用 A 和 B,这可能会有所帮助。

相反,如果您没有很多类,但有大量对 f() 和 g() 的调用,您可能会这样做:

struct C {
  C(A *ap,B *bp) : a(*ap), b(*bp) { }
  void f() { a.f(); }
  void g() { b.g(); }
  void h1() 
  {
    f();  // well at least the call is clean here
    g();
  }
  void h2()
  {
    f(); // and clean here
    g();
  }

  A &a;
  B &b;
};

如果您没有这两种情况,则每次都使用正确的对象,例如你所做的可能是最好的。

I'm imagining you have a situation like this:

struct A {
  void f();
};

struct B {
  void g();
};

struct C : virtual A, virtual B {
  C(A *ap, B *bp) 
    : A(ap), B(bp)  // This doesn't actually work -- theoretical
  {
  }

  void h() 
  { 
     f(); // calls A::f()
     g(); // calls B::g();
  }
};

Normally, when you create a C, you would be creating new As and Bs, but you would like to re-use existing ones instead, but still treat it like inheritance so that you don't have to explicitly specify which object to call.

Unfortunately, C++ doesn't support this. There are a couple of options:

You can make proxy classes that defer the function calls:

struct AProxy {
  AProxy(A *ap) : a(*ap) { }
  void f() { a.f(); }

  A &a;
};

struct BProxy {
  BProxy(B *bp) : b(*bp) { }
  void g() { b.g(); }

  B &b;
};

struct C : AProxy, BProxy {
  C(A *ap,B *bp) : AProxy(ap), BProxy(bp) { }

  void h()
  {
    f(); // calls AProxy::f() which calls a.f()
    g(); // calls BProxy::g() which calls b.g()
  }
};

This may help if you are using A's and B's in lots of different places.

If instead, you don't have many classes, but lots of calls to f() and g(), you might just do this:

struct C {
  C(A *ap,B *bp) : a(*ap), b(*bp) { }
  void f() { a.f(); }
  void g() { b.g(); }
  void h1() 
  {
    f();  // well at least the call is clean here
    g();
  }
  void h2()
  {
    f(); // and clean here
    g();
  }

  A &a;
  B &b;
};

If you don't have either of these cases, then just using the proper object each time like you were doing may be best.

无法回应 2024-12-12 14:31:13

更新回复

听起来你想要的实际上是工厂模式。我将使用日志记录作为示例,其中我假设在一个配置中您想要记录日志,而在另一个配置中您可能不希望这样做:

// logger_interface.h
class LoggerInterface {
   public:
      virtual ~LoggerInterface() {}
      virtual void Log(const string& message) = 0;
   protected:
      LoggerInterface() {}
};

第一步是创建一个纯虚拟接口,表示可配置的行为,如上面的例子。然后,我们将创建一个工厂函数,该函数可以根据配置构造一个工厂函数:

// logger_factory.h
LoggerInterface* CreateLogger(LoggerOptions options);

在实现工厂时,我们隐藏不同的实现:

// logger_factory.cc
class DoNotLogLogger : public LoggerInterface {
   public:
      DoNotLogLogger() {}
      virtual ~DoNotLogLogger() {}
      virtual void Log(const string& message) {}
};

class LogToStdErrLogger : public LoggerInterface {
   public:
      LogToStdErrLogger() {}
      virtual ~LogToStdErrLogger() {}
      virtual void Log(const string& message) {
         std::cout << message << std::endl; 
       }
};

LoggerInterface* CreateLogger(LoggerOptions options) {
    if (options.IsLoggingEnabled() && options.ShouldLogToStdErr()) {
      return new LogToStdErrLogger;
    }
    return new DoNotLogLogger;
}

以这种方式动态创建的对象没有理由需要是全局的;事实上,使其全球化是一个非常糟糕的主意。只需在需要的地方创建它,并将其作为参数传递给需要它的函数即可。

原始回复

继承不是您要找的词。基本上,您要求的是一个静态函数:

class ClassName {
   public:
       static void methodName();
};

在上面,可以使用ClassName::methodName()调用methodName,而不需要名为ClassName 的类的特定实例。但是,如果您要这样做,则更符合 C++ 风格约定,使其成为命名空间中的独立函数,如:

namespace name_of_namespace {
void functionName();
}

使用 name_of_namespace::functionName() 调用上述内容,如前所述例如,除了更容易更改或删除前缀(例如通过 using 指令)的好处之外。

注意:从设计的角度来看,如果独立或静态函数不依赖于任何状态(传递给它的参数除外),并且不可能有替代实现,则应仅使用它。一旦有状态或替代实现,您确实应该传递封装该状态的对象,即使这样做很痛苦,因为传递对象使配置更容易,使测试中的模拟更容易,并避免线程问题。

Updated response:

Its sounds like what you want is actually the Factory pattern. I'm going to use logging as an example, where I assume that in one configuration you want to log and in another you might not want to:

// logger_interface.h
class LoggerInterface {
   public:
      virtual ~LoggerInterface() {}
      virtual void Log(const string& message) = 0;
   protected:
      LoggerInterface() {}
};

The first step is to create a pure virtual interface representing the behavior that is configurable as in the example above. We will then create a factory function that can construct one based on configuration:

// logger_factory.h
LoggerInterface* CreateLogger(LoggerOptions options);

When implementing the factory, we keep the different implementations hidden:

// logger_factory.cc
class DoNotLogLogger : public LoggerInterface {
   public:
      DoNotLogLogger() {}
      virtual ~DoNotLogLogger() {}
      virtual void Log(const string& message) {}
};

class LogToStdErrLogger : public LoggerInterface {
   public:
      LogToStdErrLogger() {}
      virtual ~LogToStdErrLogger() {}
      virtual void Log(const string& message) {
         std::cout << message << std::endl; 
       }
};

LoggerInterface* CreateLogger(LoggerOptions options) {
    if (options.IsLoggingEnabled() && options.ShouldLogToStdErr()) {
      return new LogToStdErrLogger;
    }
    return new DoNotLogLogger;
}

There is no reason why the object that you create dynamically in this way needs to be global; in fact, making it global is a really bad idea. Just create it where you need it, and pass it as a parameter to the functions that need it.

Original response:

Inheritance isn't the word you are looking for. Basically, what you are asking for is a static function:

class ClassName {
   public:
       static void methodName();
};

In the above, methodName can be invoked using ClassName::methodName() without requiring a specific instance of the class named ClassName. However, if you are to do this, it is more consistent with C++ style conventions to make it a freestanding function in a namespace like:

namespace name_of_namespace {
void functionName();
}

The above is invoked using name_of_namespace::functionName() as in the previous example, except with the benefit that it is easier to change or remove the prefix (e.g. via a using directive).

NOTE: from a design standpoint, you should only use a freestanding or static function if it does not rely on any state (other than the parameters passed to it) and there is no possibility of alternative implementations. As soon as there is state or alternative implementations, you really should pass around an object encapsulating this state, even if it is a pain to do, since passing around the object makes it easier to configure, makes it easier to mock-out in tests, and avoids threading issues.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文