草庐IT

C++ 接口(interface)、继承、多态性

coder 2024-02-25 原文

想象一下这个场景:

  • 接口(interface)I1:m1(),由C1类实现
  • 接口(interface)I2:m2(),由C2类实现
  • 接口(interface)I3:m3(),由C3类实现

我想定义接受参数 arg 的函数。

void f1(I1 arg) {
    use m1()
}

void f2([I1, I2] arg) {
    use m1() and m2()
}

void f3([I2, I3] arg) {
    use m2() and m3()
}

然后我要定义:

  • 一个“union ”接口(interface) I123,它具有所有方法,由 C123
  • 实现
  • 一个“union ”类C123,它继承现有类C1C2C3 的实现方法。

然后我想实例化C123并将其与f1f2f3一起使用。

C123 obj;

f1(obj);
f2(obj);
f3(obj);

问题

  1. 这在 C++ 中可行吗?
  2. 没有接口(interface)是否可行?例如。函数 f2 将采用 [C1, C2] 而不是 [I1, I2]

代码

#include <string>
#include <iostream>

using namespace std;

class C1 {
protected:
  int i;
public:
  int getI() const { return i; }
  void setI(int i_) { i = i_; }
};

class C2 {
protected:
  string s;
public:
  string getS() const { return s; }
  void setS(string s_) { s = s_; }
};

class C3 {
protected:
  float f;
public:
  float getF() const { return f; }
  void setF(float f_) { f = f_; }
};

class C23 : public C2, public C3 {};
class C123 : public C1, public C2, public C3 {};

void f3(C23 arg) {
  arg.setS(to_string(arg.getF()));
}


int main() {

  C123 obj;

  f3(obj);

  std::cout << obj.getS();
}

错误信息

a.cc: In function ‘int main()’:
a.cc:42:9: error: could not convert ‘obj’ from ‘C123’ to ‘C23’
   f3(obj);

最佳答案

  1. Is this possible in C++?

是的,可以用 C++ 实现。

Example solution using interfaces

#include <string>
#include <iostream>

using namespace std;

class I1 {
public:
    virtual int getI() const = 0;
    virtual void setI(int i) = 0;
};

class I2 {
public:
    virtual string getS() const = 0;
    virtual void setS(string s) = 0;
};

class I3 {
public:
    virtual float getF() const = 0;
    virtual void setF(float f) = 0;
};

class C1 : public I1 {
protected:
    int i;
public:
    int getI() const { return i; }
    void setI(int i_) { i = i_; }
};

class C12 : public I1, public I2 {
protected:
    int i;
    string s;
public:
    int getI() const { return i; }
    void setI(int i_) { i = i_; }
    string getS() const { return s; }
    void setS(string s_) { s = s_; }
};

class C123 : public I1, public I2, public I3 {
protected:
    int i;
    string s;
    float f;
public:
    int getI() const { return i; }
    void setI(int i_) { i = i_; }
    string getS() const { return s; }
    void setS(string s_) { s = s_; }
    float getF() const { return f; }
    void setF(float f_) { f = f_; }
};

template<class T>
void f1(const T& c1)
{
    cout << "f1:\n";
    cout << "  getI: " << c1.getI() << endl;
}

template<class T>
void f2(const T& c12)
{
    cout << "f2:\n";
    cout << "  getI: " << c12.getI() << endl;
    cout << "  getS: " << c12.getS() << endl;
}

template<class T>
void f3(const T& c23)
{
    cout << "f3:\n";
    cout << "  getS: " << c23.getS() << endl;
    cout << "  getF: " << c23.getF() << endl;
}

void test()
{
    C1 c1;
    c1.setI(1);
    f1(c1);

    cout << "\n===== " << endl;

    C12 c12;
    c12.setI(12);
    c12.setS("str12");
    f1(c12);
    f2(c12);

    cout << "\n===== " << endl;

    C123 c123;
    c123.setI(123);
    c123.setF(1.23f);
    c123.setS("str123");
    f1(c123);
    f2(c123);
    f3(c123);

    cout << "\n===== " << endl;
}

int main()
{
    test();
}
  1. Is it possible without interfaces? Eg. function f2 would take [C1, C2] instead of [I1, I2].

是的,没有接口(interface)也可以做到这一点。

Solution using virtual inheritance (without using interfaces) :

#include <string>
#include <iostream>

using namespace std;

class C1 {
protected:
    int i;
public:
    int getI() const { return i; }
    void setI(int i_) { i = i_; }
};

class C2 {
protected:
    string s;
public:
    string getS() const { return s; }
    void setS(string s_) { s = s_; }
};

class C3 {
protected:
    float f;
public:
    float getF() const { return f; }
    void setF(float f_) { f = f_; }
};

class C12 : public virtual C1, public virtual C2
{
};

class C23 : public virtual C2, public virtual C3
{
};

class C123 : public virtual C1, public virtual C12, public virtual C23
{
};


void f1(const C1& c1)
{
    cout << "f1:\n";
    cout << "  getI: " << c1.getI() << endl;
}

void f2(const C12& c12)
{
    cout << "f2:\n";
    cout << "  getI: " << c12.getI() << endl;
    cout << "  getS: " << c12.getS() << endl;
}

void f3(const C23& c23)
{
    cout << "f3:\n";
    cout << "  getS: " << c23.getS() << endl;
    cout << "  getF: " << c23.getF() << endl;
}

void test()
{
    C1 c1;
    c1.setI(1);
    f1(c1);

    cout << "\n===== " << endl;

    C12 c12;
    c12.setI(12);
    c12.setS("str12");
    f1(c12);
    f2(c12);

    cout << "\n===== " << endl;

    C123 c123;
    c123.setI(123);
    c123.setF(1.23f);
    c123.setS("str123");
    f1(c123);
    f2(c123);
    f3(c123);

    cout << "\n===== " << endl;
}

int main()
{
    test();
}

一些解释。如果你需要你的 f2 只接受 C1 和 C2(没有 C3),那么它必须是在 C1 和 C2 上都继承的独立类型。 f3 也一样。然后,如果您遵循该逻辑并在不使用虚拟继承的情况下创建类 C12C23,那么您现在应该从 C12 和 C23 继承的 C123 最终将具有多个拷贝C2,当您调用 f2 和 f3 时,您会从 getS 获得不同的值。虚拟继承确保在继承层次结构中只有一个类的拷贝。

a "union" class C123 which inherits implemented methods from existing classes C1, C2, C3

Solution that use virtual inheritance and interfaces

#include <string>
#include <iostream>

using namespace std;

class I1 {
public:
    virtual int getI() const = 0;
    virtual void setI(int i) = 0;
};

class I2 {
public:
    virtual string getS() const = 0;
    virtual void setS(string s) = 0;
};

class I3 {
public:
    virtual float getF() const = 0;
    virtual void setF(float f) = 0;
};

class I12 : virtual public I1, virtual public I2 {};
class I23 : virtual public I2, virtual public I3 {};
class I123 : virtual public I12, virtual public I23 {};

class C1 : virtual public I1 {
protected:
    int i;
public:
    int getI() const { return i; }
    void setI(int i_) { i = i_; }
};

class C2 : virtual public I2 {
protected:
    string s;
public:
    string getS() const { return s; }
    void setS(string s_) { s = s_; }
};

class C3 : virtual public I3 {
protected:
    float f;
public:
    float getF() const { return f; }
    void setF(float f_) { f = f_; }
};

class C12 : public I12, public C1, public C2 {};
class C123 : public I123, public C1, public C2, public C3 {};

void f1(const I1& c1)
{
    cout << "f1:\n";
    cout << "  getI: " << c1.getI() << endl;
}

void f2(const I12& c12)
{
    cout << "f2:\n";
    cout << "  getI: " << c12.getI() << endl;
    cout << "  getS: " << c12.getS() << endl;
}

void f3(const I123& c23)
{
    cout << "f3:\n";
    cout << "  getS: " << c23.getS() << endl;
    cout << "  getF: " << c23.getF() << endl;
}

void test()
{
    C1 c1;
    c1.setI(1);
    f1(c1);

    cout << "\n===== " << endl;

    C12 c12;
    c12.setI(12);
    c12.setS("str12");
    f1(c12);
    f2(c12);

    cout << "\n===== " << endl;

    C123 c123;
    c123.setI(123);
    c123.setF(1.23f);
    c123.setS("str123");
    f1(c123);
    f2(c123);
    f3(c123);

    cout << "\n===== " << endl;
}

int main()
{
    test();
}

所有解决方案都应产生此输出:

f1:
  getI: 1

=====
f1:
  getI: 12
f2:
  getI: 12
  getS: str12

=====
f1:
  getI: 123
f2:
  getI: 123
  getS: str123
f3:
  getS: str123
  getF: 1.23

=====

关于C++ 接口(interface)、继承、多态性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43430511/

有关C++ 接口(interface)、继承、多态性的更多相关文章

  1. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  2. ruby - 使用 `+=` 和 `send` 方法 - 2

    如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:

  3. postman接口测试工具-基础使用教程 - 2

    1.postman介绍Postman一款非常流行的API调试工具。其实,开发人员用的更多。因为测试人员做接口测试会有更多选择,例如Jmeter、soapUI等。不过,对于开发过程中去调试接口,Postman确实足够的简单方便,而且功能强大。2.下载安装官网地址:https://www.postman.com/下载完成后双击安装吧,安装过程极其简单,无需任何操作3.使用教程这里以百度为例,工具使用简单,填写URL地址即可发送请求,在下方查看响应结果和响应状态码常用方法都有支持请求方法:getpostputdeleteGet、Post、Put与Delete的作用get:请求方法一般是用于数据查询,

  4. ruby-on-rails - Rails 单表继承 : How to override the value written to the type field - 2

    在我的系统中,我已经定义了STI。Dog继承自Animal,在animals表中有一个type列,其值为"Dog"。现在我想让SpecialDog继承自dog,只是为了在某些特殊情况下稍微修改一下行为。数据还是一样。我需要通过SpecialDog运行的所有查询,以返回数据库中类型为Dog的值。我的问题是因为我有一个type列,rails将WHERE"animals"."type"IN('SpecialDog')附加到我的查询中,所以我不能获取原始的Dog条目。所以我想要的是以某种方式覆盖rails在通过SpecialDog访问数据库时使用的值,使其表现得像Dog。有没有办法覆盖用于类型

  5. ruby - 如何计算 Liquid 中的变量 +1 - 2

    我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我

  6. arrays - Ruby 数组 += vs 推送 - 2

    我有一个数组数组,想将元素附加到子数组。+=做我想做的,但我想了解为什么push不做。我期望的行为(并与+=一起工作):b=Array.new(3,[])b[0]+=["apple"]b[1]+=["orange"]b[2]+=["frog"]b=>[["苹果"],["橙子"],["Frog"]]通过推送,我将推送的元素附加到每个子数组(为什么?):a=Array.new(3,[])a[0].push("apple")a[1].push("orange")a[2].push("frog")a=>[[“苹果”、“橙子”、“Frog”]、[“苹果”、“橙子”、“Frog”]、[“苹果”、“

  7. ruby-on-rails - rails 多态关联(遗留数据库) - 2

    我使用的是遗留数据库,所以我无法控制数据模型。他们使用了很多多态链接/连接表,就像这样createtableperson(per_ident,name,...)createtableperson_links(per_ident,obj_name,obj_r_ident)createtablereport(rep_ident,name,...)其中obj_name是表名,obj_r_ident是标识符。因此链接的报告将按如下方式插入:insertintoperson(1,...)insertintoreport(1,...)insertintoreport(2,...)insertint

  8. += 的 Ruby 方法 - 2

    有没有办法让Ruby能够做这样的事情?classPlane@moved=0@x=0defx+=(v)#thisiserror@x+=v@moved+=1enddefto_s"moved#{@moved}times,currentxis#{@x}"endendplane=Plane.newplane.x+=5plane.x+=10putsplane.to_s#moved2times,currentxis15 最佳答案 您不能在Ruby中覆盖复合赋值运算符。任务在内部处理。您应该覆盖+,而不是+=。plane.a+=b与plane.a=

  9. ruby-on-rails - 为什么 DataMapper 使用混合与继承? - 2

    所以我只是对此感到好奇:DataMapper为其模型使用混合classPostincludeDataMapper::Resource虽然active-record使用继承classPost有谁知道为什么DataMapper选择这样做(或者为什么AR选择不这样做)? 最佳答案 它允许您从另一个不是DM类的类继承。它还允许动态地将DM功能添加到类中。这是我正在处理的模块中的类方法:defdatamapper_classklass=self.dupklass.send(:include,DataMapper::Resource)klass

  10. ruby - Sinatra + Heroku + Datamapper 使用 dm-sqlite-adapter 部署问题 - 2

    出于某种原因,heroku尝试要求dm-sqlite-adapter,即使它应该在这里使用Postgres。请注意,这发生在我打开任何URL时-而不是在gitpush本身期间。我构建了一个默认的Facebook应用程序。gem文件:source:gemcuttergem"foreman"gem"sinatra"gem"mogli"gem"json"gem"httparty"gem"thin"gem"data_mapper"gem"heroku"group:productiondogem"pg"gem"dm-postgres-adapter"endgroup:development,:t

随机推荐