我遇到了抽象/虚拟类的问题,这里是问题的复制:
#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 {} 没有工作,总是给出相同的编译错误(上面的那个)。也许我需要改变的不仅仅是继承中的虚拟?
答案 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”,它应该按预期工作。