基类的构造函数中调用了虚函数。

setdefault 2007-11-06 05:02:12
//如下代码:
abstract class baseclass{
baseclass(){
callA();
}
virtual void callA();
}

class newclass:basseclass{
newclass();
override void callA(){};
}

baseclass中callA()因为会出现初始化顺序错误会出现警告,问题是这种情况下如何才是正确的使用多态的方法?

...全文
224 19 打赏 收藏 转发到动态 举报
写回复
用AI写文章
19 条回复
切换为时间正序
请发表友善的回复…
发表回复
setdefault 2007-11-06
  • 打赏
  • 举报
回复
谢谢各位的热心帮助。

特别感谢yzh提供的建议。
setdefault 2007-11-06
  • 打赏
  • 举报
回复
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;

namespace ConsoleApplication4
{
public interface IBuilder
{
void callA();

}

public class Director
{

private IBuilder builder;

public Director(IBuilder builder)
{
this.builder = builder;
construct();
}
// 将部件partA partB partC最后组成复杂对象
//这里是将车轮 方向盘和发动机组装成汽车的过程
public void construct()
{
builder.callA();

}

}


public class Builder1 : IBuilder
{

public void callA()
{
Console.WriteLine(@"It's in builder1.");
}
}

public class Builder2 : IBuilder
{

public void callA()
{
Console.WriteLine(@"It's in builder2.");
}
}


class Program
{
static void Main()
{
Director d1=new Director(new Builder1());
Director d2=new Director(new Builder2());

Debug.Assert(d1!=null);
Debug.Assert(d2!=null);
Console.ReadLine();
}
}
}
这样可以。
实现IBuilder的类作为参数传递给Director的构造函数。在调用IBuilder的callA()时IBuilder对象就初始化了。
setdefault 2007-11-06
  • 打赏
  • 举报
回复
看来builder模式可行,yzh,我先试试。
soaringbird 2007-11-06
  • 打赏
  • 举报
回复
对于二楼的反例,可以考虑把 _obj = new object();放到CallA()里面。
在写这种代码时,一定要注意执行顺序。
setdefault 2007-11-06
  • 打赏
  • 举报
回复
我是单核的!:谢谢。
可能是我没有说清楚,你的代码可以运行,但我的问题不是代码不能运行,而是有潜在的漏洞。
minioreo 2007-11-06
  • 打赏
  • 举报
回复
这个试了 可以执行 不知道是否合要求
interface IMyInterface
{
void callA();
}

abstract class baseclass:IMyInterface
{
protected baseclass()
{
callA();
}




public virtual void callA()
{
Console.WriteLine("base implement!");
}


}

class newclass : baseclass
{
public newclass() { }
public override void callA()
{
Console.WriteLine("newclass implemented");
}
}



class Program
{

static void Main(string[] args)
{
newclass myn = new newclass();

}
}
setdefault 2007-11-06
  • 打赏
  • 举报
回复
我也是考虑用什么样的模式。yzh,能说说看builder模式能怎样避免这个问题?先谢了
setdefault 2007-11-06
  • 打赏
  • 举报
回复
我是单核的!:谢谢。
还是不太行。
vwxyzh 2007-11-06
  • 打赏
  • 举报
回复
@soaringbird
编译确实没有警告,代码分析会有警告
@lz
考虑用Builder模式
setdefault 2007-11-06
  • 打赏
  • 举报
回复
soaringbird :谢谢。
如果是sealed类是可以的。当有派生类时会在构造函数初始化时出现问题。就像2楼yzh所描述的那样。
setdefault 2007-11-06
  • 打赏
  • 举报
回复
平民百姓:非常感谢
我希望派生类构造完成以后对callA的调用时透明的。不需要在子类中进行维护。
完成newclass编码的人不需要了解在类使用时的场景,类使用的人也不需要记住baseclass bc=new baseclass(); 后还要bc.callA(); 减少编码出错的概率。

interface IMyInterface{
void callA();
}

abstract class baseclass:IMyInterface
{
protected baseclass()
{
callA();
}
}

class newclass : baseclass
{

public newclass()
{
//不需要在此处做处理
}
public override void callA()
{
//something here
}
}
soaringbird 2007-11-06
  • 打赏
  • 举报
回复
构造函数中调用抽象/虚拟方法也是可以的,也没有发现编译警告,用这种方法实现差异化的构造也是行得通的
minioreo 2007-11-06
  • 打赏
  • 举报
回复
基类callA函数声明为abstract或者加上基类实现不可以么?
北京的雾霾天 2007-11-06
  • 打赏
  • 举报
回复
因为构造(楼主说的是初始化)的时候只是对类的一此初始设置,比如变量初始,设置默认的属性等,这个过程并不适合进行过多的逻辑上的处理,一切和逻辑有关的代码可以都放到独的类的方法来处理,在构造的时候处理的复杂的逻辑只有负面的影响,不会给设计带来什么太有利的事情。类在初始化后可以通过调用它的方法来进行逻辑上的处理,这是合适的。
setdefault 2007-11-06
  • 打赏
  • 举报
回复
平民百姓:谢谢。这点我同意。
只是想利用多态来自动解决派生类初始化时的差异性处理。能提些建议么?谢谢!
setdefault 2007-11-06
  • 打赏
  • 举报
回复
vwxyzh:谢谢。
你说的这个我知道。正是因为如此,如何尝试用多态,让每个派生类在构造的时候能执行callA中相应的操作(当然可以不执行callA)?
北京的雾霾天 2007-11-06
  • 打赏
  • 举报
回复
如果是自己设计的类,则改掉这个做法,不要在构造函数中调用虚方法,如果一定要在构造以后调用这个虚方法,那么最好是在使用New建立对象后主动的调用虚方法,比如:
baseclass bc=new baseclass();
bc.callA();

这样就避免了任何初始化的问题,并且是合理的。
不需要也不可以把虚方法在构造函数中调用。
vwxyzh 2007-11-06
  • 打赏
  • 举报
回复
构造函数中不要调用任何未封闭的方法,因为虚方法可能会调用了未初始化的字段
反例:
    abstract class baseclass
{
protected baseclass()
{
callA();
}
public abstract void callA();
}

class newclass : baseclass
{
object _obj;
public newclass()
{
_obj = new object();
}
public override void callA()
{
Console.WriteLine(_obj.GetType());//空引用
}
}
minioreo 2007-11-06
  • 打赏
  • 举报
回复
abstract class baseclass
{
protected baseclass()
{
callA();
}
public abstract void callA();
}

class newclass : baseclass
{
public newclass() { }
public override void callA()
{
Console.WriteLine("new class implement!");
}
}



class Program
{

static void Main(string[] args)
{
baseclass mybase = new newclass();

}
}

110,534

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

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