代码之家  ›  专栏  ›  技术社区  ›  cpf

抽象对象不能声明

  •  3
  • cpf  · 技术社区  · 14 年前

    我对抽象/虚拟类有问题,这里有一个问题的复制:

    #include <iostream>
    
    class A
    {
    protected:
        virtual std::string getDateTime() = 0;
        virtual void Write(std::string data, bool addDate) = 0;
        virtual bool CheckFile() = 0;
        virtual bool OpenFile(std::string path) = 0;
        virtual void CloseFile() = 0;
    };
    
    class B
        : public A
    {
    public:
        virtual std::string ToString() { return ""; };
        virtual void Write(std::string data) { };
    };
    
    class C
        : public A
    {
    protected:
        std::string getDateTime()
        {
            return "TODAY";
        };
    
        void Write(std::string data, bool addDate)
        {
            std::cout << "BasicClassA Write" << std::endl;
        };
    
        bool CheckFile()
        {
            std::cout << "BasicClassA CheckFile" << std::endl;
            return true;
        };
    
        bool OpenFile(std::string path)
        {
            std::cout << "BasicClassA OpenFile" << std::endl;
            return true;
        };
    
        void CloseFile()
        {
            std::cout << "BasicClassA CloseFile" << std::endl;
        };
    };
    
    class D
        : public B,
          public C
    {
    public:
        BasicClassB();
        virtual ~BasicClassB();
    
        std::string ToString()
        {
            return "BasicClassB tostring";
        };
    
        void Write(std::string data)
        {
            std::cout << "BasicClassB Write" << std::endl;
        };
    };
    
    int main(int ac, char *av[])
    {
        BasicClassB b;
        std::cout << b.ToString() << std::endl;
        b.Write("");
        return 0;
    }
    

    这有一个编译错误:

    ../src/main.cpp:在函数int main(int,char**)中:
    ../src/main.cpp:82:错误:无法将变量b声明为抽象类型BasicClassB
    ../src/main.cpp:64:注意:因为以下虚拟函数是纯在BasicClassB中使用的:
    ../src/main.cpp:13:注意:虚拟std::字符串BaseClassA::getDateTime()
    ../src/main.cpp:14:注意:虚拟void BaseClassA::Write(std::string,bool)
    ../src/main.cpp:15:注意:虚拟bool BaseClassA::CheckFile()
    ../src/main.cpp:16:注意:虚拟bool BaseClassA::OpenFile(std::string)
    ../src/main.cpp:17:注意:虚拟void BaseClassA::CloseFile()

    也许我遗漏了这一点,但是BasicClassA(即BasicClassA)的实现应该包含这些函数,而且由于BasicClassB也是BasicClassA的子类,所以它也应该包含这些函数?

    我错过了什么?我该怎么做才能编译这个文件?

    [ 编辑 ] I updated the class names as suggested by the comment
    需要澄清的是:我在A级使用纯虚拟 强制任何 来实现孩子们的功能。

    似乎虚拟继承是我所需要的,然而,在我的情况下,我似乎没有找到正确的方法来做这件事。。。

    目标是有几个类似接口的“基类”,强制子类实现函数,但是这些子类的任何子类都应该继承重写的函数(就像虚拟继承一样)

    但是,使用 类Any:public virtual Anyother{} 不工作,并且总是给出相同的编译错误(如上所述)。也许我需要改变的不仅仅是继承中的虚拟?

    4 回复  |  直到 14 年前
        1
  •  4
  •   Douglas Leeder    14 年前

    默认情况下,C++中没有这样的工作方式——你想要一个菱形继承模式,但是在C++中你得到了独立的根:所以BasicClassA和BaseClassB每个都有自己的BaseCasa(VTABLE和实例变量)。

    你可能想用 Virtual Inheritance .

    对于非虚拟继承的更清晰的概念:

    #include <iostream>
    
    
    class A
    {
        public:
            A(int x) {m_a = x;}
            virtual ~A() {}
            int m_a;
            virtual int getA() {return m_a;}
    };
    
    class B : public A
    {
        public:
            B() : A(1) {}
    };
    
    class C : public A
    {
        public:
            C() : A(2) {}
    };
    
    class D : public B,
              public C
    {
    };
    
    void useB(B* b)
    {
        std::cout << "useB:" << b->getA() << std::endl;
    }
    
    void useC(C* c)
    {
        std::cout << "useC:" << c->getA() << std::endl;
    }
    
    int main()
    {
        D* d = new D();
        useB(d);
        useC(d);
    
        return 0;
    }
    

    这将产生输出:

    useB:1
    useC:2
    

    这个例子展示了虚拟继承,以及你想要的混合行为。

    #include <iostream>
    
    
    class A
    {
        public:
            A(int x) {m_a = x;}
            virtual ~A() {}
            int m_a;
            virtual int getA() {return m_a;}
            virtual int virt() = 0;
    };
    
    class B : virtual public A
    {
        public:
            B() : A(1) {}
    };
    
    class C : virtual public A
    {
        public:
            C() : A(2) {}
            virtual int virt() {return 42;}
    };
    
    class D : public B,
              public C
    {
        public:
            D() : A(3) {}
    };
    
    
    
    void useB(B* b)
    {
        std::cout << "useB:" << b->getA() << std::endl;
    }
    
    void useC(C* c)
    {
        std::cout << "useC:" << c->getA() << std::endl;
        std::cout << "useC-virt:" << c->virt() << std::endl;
    }
    
    int main()
    {
        D* d = new D();
        useB(d);
        useC(d);
    
        return 0;
    }
    

    输出:

    useB:3
    useC:3
    useC-virt:42
    

    注意:C和B的构造函数在设置m_a时没有发言权,m_a是D()构造函数初始化列表的控制器。

    编辑: 将虚拟应用于代码:

    #include <iostream>
    
    class A
    {
    protected:
        virtual std::string getDateTime() = 0;
        virtual void Write(std::string data, bool addDate) = 0;
        virtual bool CheckFile() = 0;
        virtual bool OpenFile(std::string path) = 0;
        virtual void CloseFile() = 0;
    };
    
    class B
        : virtual public A
    {
    public:
        virtual std::string ToString() { return ""; };
        virtual void Write(std::string data) { };
    };
    
    class C
        : virtual public A
    {
    protected:
        std::string getDateTime()
        {
            return "TODAY";
        };
    
        void Write(std::string data, bool addDate)
        {
            std::cout << "C Write" << std::endl;
        };
    
        bool CheckFile()
        {
            std::cout << "C CheckFile" << std::endl;
            return true;
        };
    
        bool OpenFile(std::string path)
        {
            std::cout << "C OpenFile" << std::endl;
            return true;
        };
    
        void CloseFile()
        {
            std::cout << "C CloseFile" << std::endl;
        };
    };
    
    class D
        : public B,
          public C
    {
    public:
        std::string ToString()
        {
            return "D tostring";
        };
    
        void Write(std::string data)
        {
            std::cout << "D Write" << std::endl;
        };
    };
    
    int main(int ac, char *av[])
    {
        D b;
        std::cout << b.ToString() << std::endl;
        b.Write("");
        return 0;
    }
    
        2
  •  1
  •   JP19JP19    14 年前

    BaseClassA有5个纯虚函数。即使只有一个纯虚函数的类也是一个“抽象类”。纯虚拟函数(简而言之)的目的是禁止创建抽象类的对象。

    为了实例化BaseClassB,它需要定义您在BaseClassA中声明为纯虚拟的所有5个函数。(如果没有这些定义,BaseClassB也会变得抽象,因此您不能从中创建对象)。

        3
  •  1
  •   ereOn    14 年前

    BasicClassB 只来源于 BaseClassA 这是一个 抽象类 因为这些方法:

    virtual std::string getDateTime() = 0;
    virtual void Write(std::string data, bool addDate) = 0;
    virtual bool CheckFile() = 0;
    virtual bool OpenFile(std::string path) = 0;
    virtual void CloseFile() = 0;
    

    纯虚拟 .

    错误信息非常清楚:能够实例化 基本分类 必须 提供上述方法的实施。

    另外,请注意您对 Write 在里面 基本分类 :

    virtual void Write(std::string data) { };
    

    不同于 基类 :

    virtual void Write(std::string data, bool addDate) = 0;
    

    所以这个方法仍然需要实现 基本分类 成为瞬间的。

        4
  •  0
  •   Matthieu kelly    14 年前

    在函数中添加“=0”意味着它们是 纯粹地 虚拟的,必须在子类中实现。这显然不是你想要的。如果从基类中具有实现的函数中删除“=0”,则它应该按预期工作。