C++公有继承中基类公有成员函数为何变为私有?
问题描述
基类Potential包含public成员函数r()、l()、s()、j()等,通过public继承的派生类HammachePotential对象调用这些函数时,编译器报错称对应的派生类私有成员不可访问,但Mr()函数无此问题。
基类代码
#define POTENTIALS_HPP #include <cmath> #include "Matrix.hpp" #include "Physics_constants.hpp" #include "PotentialData.hpp" class Potential { public: Potential() {} Potential(int l, int s, int j, double Mmu) : m_l(l), m_s(s), m_j(j), m_Mmu(Mmu){} virtual void setL(int) = 0; virtual void setS(int) = 0; virtual void setJ(int) = 0; virtual void setR(double) = 0; ushort l() const {return m_l;} ushort s() const {return m_s;} ushort j() const {return m_j;} double r() const {return m_r;} double Mr() const {return m_Mmu;} ~Potential() {} virtual Matrix<double> operator () () const = 0; virtual Matrix<double> operator () (double) = 0; Matrix<double> Veff() const { if (m_l==0 || m_r == 0) return (*this)(); Matrix<double> p = (*this)(); Matrix<double> L(p.cols()); for (uint i=0; i<L.cols(); i++) L[i][i] = (m_l+2*i)*(m_l+2*i+1); L = L*(pow(Physics::Nuclear::hc,2)/(2*m_Mmu*m_r*m_r)); std::cout << m_Mmu << " " << m_r << std::endl; std::cout << p-L << std::endl; abort(); return p-L; } Matrix<double> Veff(double r) { setR(r); return Veff(); } protected: ushort m_l; ushort m_s; ushort m_j; double m_r; double m_Mmu; }; #endif // POTENTIALS_HPP
派生类代码
#ifndef ALPHAD_POTENTIAL_HAMMACHE_HPP #define ALPHAD_POTENTIAL_HAMMACHE_HPP #include "Physics_constants.hpp" #include "Potentials.hpp" #include <cmath> class HammachePotential : public Potential { public: HammachePotential() { m_s = 1; m_Mmu = PotentialData::Hammache::Mr;} HammachePotential(int l, int j) : Potential(l,1,j,PotentialData::Hammache::Mr) { if (l==0) V0 = 60.712; else V0 = 56.7; setLS2(l,s,j); } void setS(int) override {m_s=1;} void setL(int l) override { this->l = l; if (l==0) V0 = 60.712; else V0 = 56.7; setLS2(l,s,j); } void setJ(int j) override { this->j = j; setLS2(l,s,j); } void setR(double r) override { if (r==0) return; this->r = r; EXPR = expr(r); EXPRM1 = exprm1(EXPR); } std::tuple<int,int,int,double> getInfo() const { return {l,s,j,r}; } double getVcDepth() const { return V0; } Matrix<double> operator () () const { if (r==0) return Matrix<double>(1); double Vc = -V0*EXPRM1; double Ve = Vem(r); double Vso= VSO*EXPR*std::pow(EXPRM1,2)/r; Matrix<double> ret(1); ret[0][0] = Vc+Ve+Vso; return ret; } Matrix<double> operator () (double r) { if (r==0) return Matrix<double>(1); setR(r); double Vc = -V0*EXPRM1; double Ve = Vem(r); double Vso= VSO*EXPR*std::pow(EXPRM1,2)/r; Matrix<double> ret(1); ret[0][0] = Vc+Ve+Vso; return ret; } private: const double a = 0.65; //fm const double r0 = 1.25; //fm const double R = r0*std::pow(6.,1./3); //fm const double l2 = 4.; //fm^2 -> lambda^2 int l = 0; const int s = 1; int j = 1; int LS2; double V0; const double V1 = 2.4; //MeV const double coul = 2*Physics::alpha*Physics::Nuclear::hc; const double VSOfac0 = -V1*l2/a; double VSO; double r; double EXPR; double EXPRM1; private: inline void setLS2(int l, int s, int j) { LS2 = j*(j+1) - l*(l+1) - s*(s+1); VSO = VSOfac0*LS2; } inline double Vem(double r) const { if (r<=R) return coul*(3-std::pow(r/R,2))/(2*R); else return coul/r; } inline double expr(double r) const { return std::exp( (r-R)/a ); } inline double exprm1 (double expr) const { return 1.0/(1.0 + expr); } }; #endif // ALPHAD_POTENTIAL_HAMMACHE_HPP
编译错误
...main.cpp:184: error: ‘double HammachePotential::r’ is private within this context ...main.cpp:184:30: error: ‘double HammachePotential::r’ is private within this context 184 | std::cout << pot.r() << std::endl; | ^
l()、s()、j()方法调用时会出现同类错误,仅Mr()无报错。
问题原因与解决方案
问题根源
派生类HammachePotential中定义了私有成员变量l、s、j、r,这些名字和基类Potential的public成员函数名完全同名。在C++中,同一作用域内的同名实体(无论变量还是函数)会触发名字隐藏:派生类的变量名会覆盖基类的同名函数名,导致调用pot.r()时,编译器误将其解析为访问派生类的私有成员变量r,而非基类的public成员函数r()。
而Mr()无报错,是因为派生类中没有定义同名变量,编译器能正常找到基类的Mr()函数。
另外,派生类的设计存在冗余:基类已通过protected权限开放m_l、m_s、m_j、m_r成员,派生类无需重新定义一套私有变量,直接复用基类成员即可。
解决方案
删除派生类中冗余的私有成员变量l、s、j、r,直接使用基类的protected成员,并修改派生类成员函数的实现逻辑:
修改后的派生类关键代码片段
class HammachePotential : public Potential { public: HammachePotential() { m_s = 1; m_Mmu = PotentialData::Hammache::Mr;} HammachePotential(int l, int j) : Potential(l,1,j,PotentialData::Hammache::Mr) { if (l==0) V0 = 60.712; else V0 = 56.7; setLS2(m_l, m_s, m_j); // 使用基类成员 } void setS(int) override {m_s=1;} void setL(int l) override { m_l = l; // 赋值给基类的m_l if (l==0) V0 = 60.712; else V0 = 56.7; setLS2(m_l, m_s, m_j); } void setJ(int j) override { m_j = j; // 赋值给基类的m_j setLS2(m_l, m_s, m_j); } void setR(double r) override { if (r==0) return; m_r = r; // 赋值给基类的m_r EXPR = expr(m_r); EXPRM1 = exprm1(EXPR); } std::tuple<int,int,int,double> getInfo() const { return {m_l, m_s, m_j, m_r}; // 返回基类成员 } Matrix<double> operator () () const { if (m_r==0) return Matrix<double>(1); double Vc = -V0*EXPRM1; double Ve = Vem(m_r); double Vso= VSO*EXPR*std::pow(EXPRM1,2)/m_r; Matrix<double> ret(1); ret[0][0] = Vc+Ve+Vso; return ret; } private: // 删除原有的int l、const int s、int j、double r成员 const double a = 0.65; //fm const double r0 = 1.25; //fm const double R = r0*std::pow(6.,1./3); //fm const double l2 = 4.; //fm^2 -> lambda^2 int LS2; double V0; const double V1 = 2.4; //MeV const double coul = 2*Physics::alpha*Physics::Nuclear::hc; const double VSOfac0 = -V1*l2/a; double VSO; double EXPR; double EXPRM1; inline void setLS2(int l, int s, int j) { LS2 = j*(j+1) - l*(l+1) - s*(s+1); VSO = VSOfac0*LS2; } // 其余私有函数保持不变 };
修改说明
- 删除派生类中与基类函数同名的私有变量
l、s、j、r,消除名字冲突。 - 所有原本操作派生类私有变量的逻辑,改为操作基类的protected成员
m_l、m_s、m_j、m_r。 - 基类的
l()、s()、j()、r()函数会正常返回基类成员的值,调用不再触发权限错误。
内容的提问来源于stack exchange,提问作者Alessandro
相关产品推荐
相关产品推荐

