关于this指针(visitor模式)

博客围绕visitor设计模式展开,指出在该模式里,即便父类实现了accept方法,子类仍需重写。通过代码示例说明若子类不重写,使用父类含this指针的函数,可能导致结果错误,如boss对象调用时输出employee的结果。

前两天看visitor设计模式,其中对于每个需要添加功能的类都要加上

public void accept(visitor v)

{

   v.accept(this)    ;

}

即使父类中已经实现了这个方法,子类中还要重写。

估计与this参数有关,今天写程序试了一下。

class employee;
class boss;

class visitor
{
public:
 void visit(employee * e)
 {
  cout<<"this is in employee visit"<<endl;
 }

 void visit(boss * b)
 {
  cout<<"this is in boss visit"<<endl;
 }
};

class employee
{
public:
 void accept(visitor v)
 {
  v.visit(this);
 }
};

class boss : public employee
{
public:
 //必须对每一个类都重新写
 //因为其中涉及到this指针的问题
 void accept(visitor v)
 {
  v.visit(this);
 }
};

void main()
{
 visitor v;
 boss b;
 employee e;
 b.accept(v);
 e.accept(v);
}

如果boss类中的accept方法不重写的话,那么对boss对象的调用输出的结果是:

this is in employee visit

可见,虽然两个对象是不同的,但是如果boss对象调用父类的函数,而该函数中用到了this指针

那么结果很有可能是不对的,因为这里使用的this指针是employee类的。

<think>好的,用户问的是“不转换,直接用父类指针去调用”,也就是想用父类指针直接调用子类的特有函数。首先,我需要确认用户的问题背景。可能用户对C++的多态机制不太熟悉,或者遇到了设计上的问题,想要绕过类型转换直接调用子类方法。 首先,我要回忆C++的基本规则:父类指针只能调用父类中声明的成员函数,子类的特有函数在父类中是不可见的。所以直接调用是不可能的,必须通过类型转换。但用户明确说不转换,所以需要解释为什么不行,以及可能的替代方案。 接下来,用户可能的需求是什么?也许他们希望避免类型转换带来的复杂性或潜在风险,或者他们正在设计一个系统,希望保持接口的简洁性,不需要频繁转换指针类型。这时候需要提供替代的设计模式,比如虚函数、访问者模式或者双重分发。 然后,我需要考虑用户的潜在误解。可能用户认为父类指针指向子类对象后,就能自动拥有子类的所有方法,但实际上这是静态类型决定的。需要解释静态类型和动态类型的区别,以及C++的编译时多态和运行时多态。 另外,用户可能没有意识到,直接调用子类特有函数可能破坏面向对象的设计原则,比如里氏替换原则。如果父类指针需要调用子类特有的方法,可能说明设计上有问题,需要重新考虑类的职责划分。 接下来,我需要组织回答的结构。首先明确说明直接调用不可行,然后解释原因,再提供替代方案,最后总结设计建议。同时,要确保语言通俗易懂,避免使用过多术语,但也要准确。 可能还需要提到一些常见错误,比如使用static_cast强制转换而不检查类型,导致未定义行为。或者用户可能尝试将子类函数声明为虚函数,但发现父类中没有,所以无法覆盖。 最后,根据用户的问题,生成相关问题,比如为什么不能直接调用,虚函数的作用,设计模式的替代方案等。确保相关问题覆盖用户可能的疑问点,帮助他们深入理解。</think>在C++中,**父类指针无法直接调用子类特有的函数**,因为父类指针的静态类型(编译时类型)决定了其可见的成员函数范围。子类特有的函数在父类中未声明,因此编译器会直接报错。以下是详细解释和替代方案: --- ### **1. 为什么无法直接调用?** - **静态类型限制**:父类指针的静态类型是父类,编译器只会检查父类中声明的成员函数。 - **编译错误示例**: ```cpp class Base { /* 无子类函数声明 */ }; class Derived : public Base { public: void specificFunc() {} }; Base* ptr = new Derived(); ptr->specificFunc(); // 编译错误:Base中没有specificFunc() ``` --- ### **2. 替代方案(不强制转换)** #### **(1) 通过虚函数实现多态** 将子类特有函数声明为父类的虚函数,子类重写该函数: ```cpp class Base { public: virtual void commonFunc() = 0; // 纯虚函数 }; class Derived : public Base { public: void commonFunc() override { // 子类实现 } }; Base* ptr = new Derived(); ptr->commonFunc(); // 正确:通过虚函数调用子类实现 ``` #### **(2) 双重分发(Double Dispatch)** 通过两次虚函数调用实现动态行为分发: ```cpp class Base; class Derived; class Visitor { public: virtual void visit(Base*) = 0; virtual void visit(Derived*) = 0; }; class Base { public: virtual void accept(Visitor* v) { v->visit(this); } }; class Derived : public Base { public: void accept(Visitor* v) override { v->visit(this); } }; // 使用时 Visitor v; Base* ptr = new Derived(); ptr->accept(&v); // 根据实际类型调用visit(Derived*) ``` #### **(3) 重新设计类结构** - **避免继承**:改用组合或策略模式,将子类特有功能封装为独立组件。 - **模板方法模式**:通过模板参数绑定具体实现。 --- ### **3. 关键原则** - **优先通过虚函数暴露接口**,而非依赖子类特有函数。 - **避免暴露子类细节**,保持父类接口的抽象性。 - **慎用强制类型转换**,除非明确知道指针的实际类型。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值