我有一个基类Base和几个派生类:Derived1,Derived2和Derived3。
我想在所有这些中都有函数funcOne,所以我可以像这样定期访问它:
Base* d1 = new Derived1();
Base* d2 = new Derived2();
Base* d3 = new Derived3();
d1->funcOne();
d2->funcOne();
d3->funcOne();
但我想在Derived1类中只有函数funcTwo。 问题是,我想这样访问它:
d1->funcTwo();
除了在基类中使用某种实现创建虚拟funcTwo之外,是否可以以某种方式执行此操作,例如
void funcTwo(){ cout << "There is no funcTwo for this class" << endl; }
其他只针对Derived1类的实现?
谢谢!
答案 0 :(得分:3)
你有两个我能想到的主要选择。
您可以在问题中概述的基类中实现虚拟funcTwo。这通常是不好的做法,因为假设funcTwo在Base,Derived2和Derived3的上下文中没有意义。如果滥用API不能编译而不仅仅是抛出错误,或者更糟糕的是,默默地失败,那就更好了。 这看起来像:
class Base() {virtual void funcTwo() {throw runtime_error("This should not be called");};
Base *d1 = new Derived1;
Base *d2 = new Derived2;
d1->funcTwo(); //fine
d2->funcTwo(); //compiles even though it doesn't make semantic sense, throws an exception
或者,你可以在Derived1中实现funcTwo。然后,您可以尝试在可能的情况下直接将指针保存到Derived1,并在不可能时使用dynamic_cast。这是首选,因为对Base :: funcTwo的直接调用将无法编译,并且您的语义更接近您实际尝试表达的内容。
Base *b = new Derived1;
Derived1 *d1 = new Derived1;
Base *d2 = new Derived2;
d1->funcTwo(); //fine
if ((d1 = dynamic_cast<Derived1*>(b)) d1->funcTwo(); //fine
if ((d1 = dynamic_cast<Derived1*>(d2)) d1->funcTwo(); //funcTwo is not called, no errors
b->funcTwo(); //fails to compile
答案 1 :(得分:1)
除了在基类[...]
中创建虚拟funcTwo之外,是否可以以某种方式执行此操作
如果您想要统一处理所有指针,则为Base*
类型。
也就是说,你可以这样做:
Derived1 *d1 = new Derived1(); // not treated as a base*
Base* b1 = d1;
Base* b2 = new Derived2();
Base* b3 = new Derived3();
d1->funcTwo(); // not treated as a base*
b1->funcOne();
b2->funcOne();
b3->funcOne();
您也可以动态投射指针(但这比我上面的代码更糟糕):
void CallFunc2(Base* b) {
if(auto d = dynamic_cast<Derived1*>(b))
d->funcTwo();
}
客户代码:
Base* b1 = new Derived1();
Base* b2 = new Derived2();
Base* b3 = new Derived3();
CallFunc2(b1); // will call Derived1::funcTwo
CallFunc2(b2); // will do nothing
CallFunc2(b3); // will do nothing
答案 2 :(得分:0)
如果您不希望成员函数完全位于Base
,您可以向下转换指向具有该函数的正确类的指针,使用{{3 }}:
Base* b = new Derived;
static_cast<Derived*>(b)->func2(); // Call function only available in `Derived`
当然,这要求指针b
实际上是指向Derived
实例的指针,或者您有未定义的行为。
注意:根据事物的类型进行这样的预测,并做不同的事情,通常被认为是糟糕的设计。
答案 3 :(得分:0)
是的,您为此目的dynamic_cast
。如果您的Base
指针是Derived1
,则演员会有效,然后您可以拨打funcTwo()
。如果不是演员表会失败。
在大多数情况下,使用dynamic_cast
是一个设计缺陷。它对于组件加载和版本控制等有用的东西很有用,你不知道哪个版本的组件正在被加载,所以你检查它是否支持更新的功能。
在你的情况下,这可能是错误的。
无论如何你必须这样做。
Base * b = getBasePtr(); // I don't know which one I got
Derived1 * d1 = dynamic_cast< Derived1 * >( b );
if( d1 )
d1->func2();
答案 4 :(得分:-1)
我认为最好的办法是使用静态方法尝试为您执行解析并执行仅存在于派生类中的函数。
class Base {
public:
virtual ~Base() {}
virtual void func1() = 0;
};
class Derived1 : public Base {
public:
virtual ~Derived1() {}
virtual void func1() { std::cout << "Derived1::func1" << std::endl; }
void func2() { std::cout << "Derived1::func2" << std::endl; }
};
class Derived2 : public Base {
public:
virtual ~Derived2() {}
virtual void func1() { std::cout << "Derived2::func1" << std::endl; }
};
void func2(Base& b) {
Derived1* d = dynamic_cast<Derived1*>(&b);
if (d) d->func2();
}
void f() {
Base* b1 = new Derived1;
Base* b2 = new Derived2;
func2(*b1);
func2(*b2);
}
这种方法会花费你一个dynamic_cast,但会保存你的vtable查找,并且还会为你提供你想要的行为。