c++模板类在继承中子类无法访问父类的成员

#c++模板类在继承中子类无法访问父类的成员


####问题:c++模板类在继承中子类无法访问父类的成员
#####解决方法:在子类访问父类时加上父类的前缀或使用this->调用


c++从入门到放弃,感觉c++了解的越多,就越不会(心累啊)
最近在写一套数据结构的模板库,遇到了很多问题,比如头文件的重复引入,定义等等,这次说说新遇到的问题,模板类的继承中子类无法访问父类的成员,
子类不能访问父类的成员在VC++中可以编译通过,而用g++就会报错

先列出我查过的资源,要转载的话注意作者的版权

  1. https://www.zhihu.com/question/28139230
  2. https://bbs.youkuaiyun.com/topics/391862079
  3. https://blog.youkuaiyun.com/u012175089/article/details/54231791
template <class T>
class Base{
public:
	T data;
	void display();
};
template <class T>
class Derive:public Base<T>{
	void show(){cout << data;}
};
//上面的代码无法编译通过,子类无法访问基类的成员变量或成员函数,
//用this访问即可,也可以直接在成员前家基类的名字Base<T>::

1.对于两个非模板继承是可直接继承.
2.对于模板类继承非模板类时,在模板声明进行解析的时候就会进行查找
3.对于继承父类是模板类的会进行名称二次查找

 模板定义阶段:刚被定义时,只有模板中独立的名字(可以理解为和模板参数无关的名字)参加查找
 模板实例化阶段:实例化模板代码时,非独立的名字才参加查找。
 //一个模板子类其实是不能在实例化之前就知道他的模板父类到底是谁,所以只能this->了

c++ 两阶段名字查找,对于非依赖模板名称的都是现场决议的,编译器不查找基类 scope,没找到就报错,编译器不查找基类,因为此时基类还是个类模板,到底是什么东西还不定呢。
然后实例化的时候进行第二阶段名字查找,这时候所有类型都是确定的,才能够查找基类 scope。
增加 this 或 Base:: 就是把对 function 的查找延迟到第二阶段,这是 c++ 标准规定的。
这里有一个带栗子的博客,可以看看比较详细:二次查找的栗子
c++继承中名字的查找

### C++ 中子继承父类时设置为 `public` 的作用及原因 在 C++ 面向对象编程中,当一个子通过 `public` 方式继承父类时,这种继承方式决定了访问控制权限以及派生对外部接口的暴露程度。以下是关于为什么需要将父类设为 `public` 的具体分析: #### 1. 访问控制权的影响 当使用 `public` 关键字进行继承时,父类中的公有成员(`public` 成员)会保持其原有的访问级别不变[^2]。这意味着这些成员对于外部世界仍然是可访问的。如果采用其他形式的继承(如 `protected` 或 `private`),则父类的公有成员会被重新定义为受保护或私有的成员。 例如: ```cpp class Base { public: void displayBase() { cout << "This is base class." << endl; } }; class DerivedPublic : public Base {}; // Public inheritance class DerivedPrivate : private Base {}; // Private inheritance int main() { DerivedPublic dp; dp.displayBase(); // 正常工作,因为是公共继承 DerivedPrivate dpr; // 下面这行会产生编译错误,displayBase 已经变为私有了 // dpr.displayBase(); return 0; } ``` 因此,为了使子能够公开地展示并允许外界调用它所继承的功能,通常会选择 `public` 继承模式。 #### 2. 接口一致性维护 设定为 `public` 还有助于维持良好的设计原则——即 Liskov 替换原则 (LSP),该原则指出任何基型的引用都可以被替换为其衍生型而不影响程序行为的有效性和正确性[^1]。换句话说,如果你有一个指向基础的对象指针或者引用,则无论实际实例属于哪个具体的派生别,只要它们都遵循相同的契约关系,就可以无缝操作而无需额外考虑内部实现细节差异。 继续上面的例子来看, ```cpp void useBase(Base* b){ b->displayBase(); } int main(){ DerivedPublic derivedPubObj; useBase(&derivedPubObj); // 可以正常运行,符合LSP DerivedPrivate derivedPrivObj; //useBase(&derivedPrivObj); // 编译失败,无法转换到Base* return 0; } ``` 这里展示了只有当使用的是 `public` 形式的继承时,才能满足上述条件;而对于那些采用了更严格限制性的继承策略来说就不一定适用了。 #### 3. 提升代码复用率与扩展能力 利用 `public` 来构建层次结构还可以极大地促进软件开发过程中的模块化思维发展,并提高整体系统的灵活性和适应未来需求变化的能力。由于所有的功能都是开放给用户的,所以开发者可以根据实际情况自由组合不同组件来创建新的解决方案,同时也方便后续添加更多特性支持。 总结而言,在大多数情况下选择让子以 `public` 方法从另一个现有实体那里获取资源是非常合理的做法,因为它不仅简化了语法表达上的复杂度而且还增强了应用程序之间的互操作性能。 ```cpp // 示例:展示如何通过public继承增强功能的同时保留原始API可用性 #include <iostream> using namespace std; class Shape{ public: virtual void draw()=0;//纯虚函数声明抽象基 }; class Circle: public Shape{ public: void draw(){cout<<"Drawing a circle"<<endl;} }; class Rectangle: public Shape{ public: void draw(){cout<<"Drawing a rectangle"<<endl;} }; int main(){ Shape *s=new Circle();//动态分配内存空间用于存储Circle型数据 s->draw(); //输出"Drawing a circle" delete s; //释放占用的空间 s=new Rectangle(); //再次改变指向目标地址至Rectangle区域 s->draw(); //此时应显示"Drawing a rectangle" delete s; return 0; } ``` 以上例子说明即使存在多态现象下仍然可以通过统一入口调用各自特化的版本完成任务执行流程管理等工作。
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小源er

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值