抽象对象无法声明

时间:2010-11-22 13:27:16

标签: c++ compilation virtual abstract-class

我遇到了抽象/虚拟类的问题,这里是问题的复制:

#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:注意:virtual std :: string BaseClassA :: getDateTime()
../src/main.cpp:14:note:virtual void BaseClassA :: Write(std :: string,bool)
../src/main.cpp:15:注意:虚拟bool BaseClassA :: CheckFile()
../src/main.cpp:16:note:virtual bool BaseClassA :: OpenFile(std :: string)
../src/main.cpp:17:note:virtual void BaseClassA :: CloseFile()

也许我在这里忽略了这一点,但是BaseClassA(作为BasicClassA)的实现应该包含这些函数,并且由于BasicClassB也是从BasicClassA子类化的,它还应该包含这些函数吗?

我错过了什么?我该怎么做才能编译呢?

[修改] I updated the class names as suggested by the comment
澄清一下:我在A类中使用纯虚拟来强迫孩子强迫任何实现这些功能。

似乎虚拟继承是我需要的,但是,在我的情况下,我似乎没有找到正确的方法来实现这一点......

目标是有几个“基类”,类似于接口,强制孩子们实现这些功能,但是那些孩子应该继承覆盖功能(就像虚拟继承一样)

然而,使用任何组合     class Any:public virtual Anyother {} 没有工作,总是给出相同的编译错误(上面的那个)。也许我需要改变的不仅仅是继承中的虚拟?

4 个答案:

答案 0 :(得分:4)

默认情况下它在C ++中不起作用 - 你想要一个钻石继承模式,但是在C ++中你会得到单独的根:所以BasicClassA和BaseClassB都有自己的BaseClassA(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;
}

答案 1 :(得分:1)

BaseClassA有5个纯虚函数。甚至一个纯虚函数的类是“抽象类”。纯虚函数(简称)的目的是禁止创建抽象类的对象。

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

答案 2 :(得分:1)

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;

纯虚拟

错误消息非常明确:为了能够实例化BasicClassB必须为前面提到的方法提供实现。

另请注意您在Write中对BasicClassB的定义:

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

BaseClassA

中的不同
virtual void Write(std::string data, bool addDate) = 0;

因此,仍然需要为BasicClassB实现此方法才能成为可实例化的。

答案 3 :(得分:0)

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