这种函数我该怎么调用?void getClass(AbstractClass &p);

shootingstars 2006-03-02 04:06:10
AbstractClass为一个抽象类,这个抽象类派生了若干个实例类。
getClass函数为一个工厂方法,根据不同情况返回一个实例对象。
示例代码下:
class AbstractClass
{
public:
void virtual fun() = 0;
};
class B : public AbstractClass
{
public:
void fun()
{
printf("B");
}
};
class C : public AbstractClass
{
public:
void fun()
{
printf("C");
}
};

B b;
C c;
void getClass(AbstractClass &p)
{
int i = rand();
if(i>10)
a = b;
else
a = c;
}

问题是我该如何调用这个函数呢?
(我是在调用Snmp++库中的int Vb::get_value(SnmpSyntax &val) const函数遇到的这个问题,SnmpSyntax为一个抽象类)
...全文
346 30 打赏 收藏 转发到动态 举报
写回复
用AI写文章
30 条回复
切换为时间正序
请发表友善的回复…
发表回复
shootingstars 2006-03-03
  • 打赏
  • 举报
回复
To happy__888([顾问团]寻开心)
我已经将Snmp++的代码改写了一下,将函数原型修改为:
int get_value(SnmpSyntax **val);

呵呵,是不是应该向Snmp++库的作者们递交一个Bug?

shootingstars 2006-03-03
  • 打赏
  • 举报
回复
我按照ox_thedarkness()的意思写了一份代码(呵呵,希望我没有理解错)
#define MaxClassSize 1000

int _tmain(int argc, _TCHAR* argv[])
{
char buf[MaxClassSize];
void *p = new(buf)C;

getClass( *((AbstractClass *)p));
(AbstractClass *)p)->fun();

return 0;
}
...可是结果不对...
虚函数表并没有被重写。
寻开心 2006-03-03
  • 打赏
  • 举报
回复
= 也是要特殊写的,没有必要为这个问题,搞得那么复杂
只要改成,传递**指针就完事了

编程的定理: 不要为迎合以前有的错误而继续错误下去
ox_thedarkness 2006-03-03
  • 打赏
  • 举报
回复
= =不过他如何重载的 operator= 阿? 需要dynamic cast把...
ox_thedarkness 2006-03-03
  • 打赏
  • 举报
回复
哦,楼上的有道理~~ 用 operator= ~~ 不过这样不能改虚函数表的说~~
寻开心 2006-03-03
  • 打赏
  • 举报
回复
就getClass(AbstractClas &p)
{
if
p = b;
else
p = c;
}
而言, 这样的设计并不好

原因如下,在调用这个函数的时候,

p只有两种可能,一个是AbstractClass 对象
这显然不现实,因为它是纯虚类, 不能有实例
另外的一个可能,p是一个继承类的实例

那么就存在这样的问题,具体执行的是p=b或者p=c这种操作
显然,b和c不是相同的类型
虽然他们都继承于公共的父类,但是在这两种不同类型之间的直接=操作,还是有潜在的危险的
除非他们被特殊的设计,以支持这种操作,否则就不应该这样来写

看看com当中,如何返回接口的,都是用**指针,保证安全性
ox_thedarkness 2006-03-03
  • 打赏
  • 举报
回复
我唯一想到的一种可能是:

这是一个不对外使用的包的内部实现部分。 他要求所有子类大小相同;或者有一个“最大的初始化子类”作初始化用。

这样,任何子类可以用等大元素的数组保存,这可以用于建立类池。 同时可以实现直接修改子类的类型...
ox_thedarkness 2006-03-03
  • 打赏
  • 举报
回复
恩,就是happy__888([顾问团]寻开心) ( ) 的意思。 这个函数绝对不是正常方式使用的。
ox_thedarkness 2006-03-03
  • 打赏
  • 举报
回复
- -b 还是不明白... 这个函数是干什么的?

void getClass(AbstractClass &p)

这个函数难道是,输入一个AbstractClass 类,将其原地改成一个他的另一个子类?



用 replacement new 办倒是办得到,不过非常不安全 ——

1 因为传入的是引用,p 的用户必须保证,你传入的地址拥有拥有足够大的缓冲,能包含可能构造的任何子类。

2 析构造函数契约问题很麻烦。输入的是引用,所以必须有一个构造了的AbstractClass 类(或者其子类),用replacement new 之前要析构他们。 另外,返回的 replacement new 的对象,从语法上很难被正确删除,需要用户非常了解 new /delete 的机制。

////////////////////////////////////////////////////////

如果是这个意思,我倒可以写一份实现给楼主参考... 不是这个意思就算了
寻开心 2006-03-03
  • 打赏
  • 举报
回复
这种做法不可以, a不能有实例,因为它是一个纯虚的函数

除非的getClass之前你就很清楚返回的对象是B或者C类型的
B b1;
C c1;
getClass(b1); // b1 = b
getClass(c1); // c1 = c

否则就不应该这样, 比如:
getClass(b1);
// b1 = c 这会有潜在的问题,不是绝对会出问题
//
shootingstars 2006-03-03
  • 打赏
  • 举报
回复
再顶一下。
楼上各位兄弟,可能理解错我的意思了。
现有一个库,提供了类似void getClass(AbstractClass &p)这样的接口,我是否可以正确调用?(如果不能调用这个函数,那这就是一个Bug了)。
这个库不是我写的,我也不想改变它的代码(尽管它是开源的)。

我只是想是不是有我不知道的关于引用对象的C++语法?
shootingstars 2006-03-03
  • 打赏
  • 举报
回复
呵呵,楼上的话让我茅舍顿开。。。
确实是我的理解错了,这个函数并不是一个工厂方法,它并不是想返回一个真实对象,而仅仅是想传递对象的属性而以。

那么调用方法也就确定了:
SmiUINT32 type = get_syntax();// 调用get_syntax()知道当前SnmpSyntax指针所指向的对象的标识
SnmpSyntax *obj = CreateClass(type);// 自己根据标识,构建一个真实对象
get_value(*obj); // 使用get_value函数传递属性,而不是对象。

谢谢happy__888([顾问团]寻开心) 了
寻开心 2006-03-03
  • 打赏
  • 举报
回复
这段代码
int Vb::get_value(SnmpSyntax &val) const
{
if (iv_vb_value)
{
val = *iv_vb_value; // iv_vb_value为SnmpSyntax *类型
if (val.valid())
return SNMP_CLASS_SUCCESS;
return SNMP_CLASS_INVALID;
}
// TM: should set val to be invalid
return SNMP_CLASS_INVALID;
}
看不出,楼主说的
void getClass(AbsClass &p)
{
if ()
p = b;
else
p = c;
}
这种意思啊;

那段代码看起来表达的是另外一个意思
int Vb::get_value(SnmpSyntax &val) const
{
如果 iv_vb_value 这个指针不空
返回这个指针,并且检测这个指针的有效性
否则
标志错误,不返回内容
}
没有返回不同类型的对象的意思啊。
当然存在可能, 传递的对象和返回的对象是不同的类的实例,但是不一定是错误的
要看具体的设计目的是什么了,以及对返回的对象如何用了
寻开心 2006-03-03
  • 打赏
  • 举报
回复
com接口的方法不同,它是返回一个已经存在的对象,供调用者来使用

而你提供的方法,不一定是这个目的
也许它并不想返回已存在的对象,而是只要获得它的一个copy或者部分的属性
那么在参数是非抽象类型的时候,是有效的做法『即便是抽象的,也可以这样理解:目的只是为了获得继承类的公共属性而已--- 函数当中的那个 = 符号 只能这样理解才是合理的』

寻开心 2006-03-03
  • 打赏
  • 举报
回复
如果SnmpSyntax不是抽象的类,结果就不同了
这个时候的传入参数可以是SnmpSyntax的对象

因为也许它只想取得继承类对象的基类属性,并不是要把继承类对象完整的带回
基类向父类的转换是正常的,可用的

注意函数里面的 = 符号, 这个执行的是一个类型的转换
并不是返回一个现有的对象

这里不是值参的问题, 因为这个是c++, 函数用的是引用类型, 改变是可以带回的
ox_thedarkness 2006-03-03
  • 打赏
  • 举报
回复
这么看,get_value只是用来获得 val 的类型信息的。
不是类型转换。



btw... 我说的是这个意思。下面的操作可以成功,但是结果耐人寻味。

//================================================
class Base{
public:
virtual void f() = 0;
virtual ~Base(){};
};

class A:public Base {
public:
void f(){ cout<<"A"<<endl; }
~A(){ cout<<"~A()"<<endl; }
};

class B:public Base {
public:
void f(){ cout<<"B"<<endl; }
~B(){ cout<<"~B()"<<endl; }
};


void setClass( Base& base, char id ){
base.~Base();
switch( id ){
case 'A': new( &base ) A;
case 'B': new( &base ) B;
default: ;//错误处理
}
}

int main(){
A a;
setClass( a, 'B' );
a.f();

Base* pb = &a;
pb->f();
}
//================================================

Base* pb = &a;
pb->f();
输出B,证明虚函数表的确被覆盖。

但是
a.f()被早绑定了、同样,退出时调用的 a.A::~A() 也是早榜定的。
shootingstars 2006-03-03
  • 打赏
  • 举报
回复
提出int Vb::get_value(SnmpSyntax &val) const在snmp++库中的实现:
//---------------[ Vb::get_value(Value &val) ]--------
int Vb::get_value(SnmpSyntax &val) const
{
if (iv_vb_value)
{
val = *iv_vb_value; // iv_vb_value为SnmpSyntax *类型
if (val.valid())
return SNMP_CLASS_SUCCESS;
return SNMP_CLASS_INVALID;
}
// TM: should set val to be invalid
return SNMP_CLASS_INVALID;
}

发现一个问题:
即使SnmpSyntax 不为抽象类,可以在外面定义SnmpSyntax 的实例,这个函数的同样存在问题:
函数内部可以改写val所指向的东西,但是这个val是值传递(实际上所有的C函数参数都是值传递),不能带到外部(即外部的val是啥类型,执行函数后还是啥类型)。。。等于这个函数啥都没做。

呵呵,有谁English比较好,发封邮件去support@agentpp.com问问。 ^_^
xinxinglc 2006-03-02
  • 打赏
  • 举报
回复
这个应该就是多态吧。我不是特别懂呵。如果父类有个虚拟的函数,直接在子类覆盖就可以了啊。用的时候,把子类的实际对象赋给父类的指针或者引用,利用自身的多态就可以正确调用的。
寻开心 2006-03-02
  • 打赏
  • 举报
回复
void getClass(AbstractClass **p)
{
if
*p = &b;
else
*p = &c;
};

main()
{
AbstractClass *p;
GetClass(&p);
}
寻开心 2006-03-02
  • 打赏
  • 举报
回复
既然是写类工厂,就看看com的原理,其中的原形
返回对象接口的,都是 void**类型
加载更多回复(10)

64,654

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧