我一直认为我理解继承,但显然我不知道。我想从子类中调用同一父类的另一个实例的受保护成员函数,如下面的示例代码所示:
#include <iostream>
class Parent {
protected:
void doStuff(){
std::cout << 5 << std::endl;
}
};
class Child : public Parent {
public:
void pubfunc(Parent* p){
p->doStuff();
}
};
int main(){
Child* c = new Child();
Parent* p = new Parent();
c->pubfunc(p);
return 0;
}
但是,此代码的编译失败了:
In member function ‘void Child::pubfunc(Parent*)’:
error: ‘void Parent::doStuff()’ is protected
error: within this context
我不想让Child
类成为friend
类的Parent
,以避免前向声明,并尽可能地转发包含子类。另外,我不想让doStuff
公开,因为在错误的情况下使用时,Parent
的内部结构会非常混乱。
为什么会发生这种错误,最优雅的解决方法是什么?
答案 0 :(得分:3)
问题主要是如果C ++允许您直接访问基类指针的非公共成员,那么只需从公共库中派生就可以轻松访问对象的数据。 / p>
这仍然是C ++类型系统中已知的漏洞,如下所示,您可以在不修改基类的情况下获得该访问权限,而无需使用强制转换或类似的东西。
在第三方面,你应该做的是通过在那里添加static
成员函数来直接在基类中支持预期用法,如下所示:
#include <iostream>
using namespace std;
class Base
{
protected:
void doStuff()
{
cout << 5 << endl;
}
static void doStuff( Base* p ) { p->doStuff(); }
};
class Derived : public Base
{
public:
void pubfunc( Base* p )
{
doStuff( p );
}
};
auto main() -> int
{
Derived d;
Base b;
d.pubfunc( &b );
}
以我的拙见,这是最清晰和优雅的。
但为了完整性,类型系统存在漏洞:
#include <iostream>
using namespace std;
class Base
{
protected:
void doStuff()
{
cout << 5 << endl;
}
};
class Derived : public Base
{
public:
void pubfunc( Base* p )
{
(p->*&Derived::doStuff)();
}
};
auto main() -> int
{
Derived d;
Base b;
d.pubfunc( &b );
}
我推荐使用static
成员函数。
答案 1 :(得分:0)
受保护的成员可以在定义它们的类中以及从该类继承的类中访问。有时它会让人们在看到这种错误时感到困惑。但实际上你为Parent对象调用了doStuff函数,如果函数调用在继承类中完成,它就不会计量。如果从main()调用doStuff函数,结果将是相同的。
答案 2 :(得分:-1)
class Parent
{
protected:
virtual void doStuff()
{
std::cout << 5 << std::endl;
}
};
class Child : public Parent
{
protected:
void doStuff() override
{
std::cout << 8 << std::endl;
}
public:
void pubfunc(Parent* p)
{
((Child*)p)->doStuff();
}
};
int main()
{
Child* c = new Child();
Parent* p = new Parent();
c->pubfunc(p); // will print 5
c->pubfunc(c); // will print 8
return 0;
}