精华内容
下载资源
问答
  • 本节书摘来自异步社区《Python面向对象编程指南》一书的第1章,第1....1.3 在基类中实现init()方法 通过实现__init()__方法来初始化一个对象。每当创建一个对象,Python会先创建一个空对象,然后调用该对象的__in...

    本节书摘来自异步社区《Python面向对象编程指南》一书中的第1章,第1.3节,作者[美]Steven F. Lott, 张心韬 兰亮 译,更多章节内容可以访问云栖社区“异步社区”公众号查看。

    1.3 在基类中实现init()方法

    通过实现__init()__方法来初始化一个对象。每当创建一个对象,Python会先创建一个空对象,然后调用该对象的__init()__函数。这个方法提供了对象内部变量以及其他一些一次性过程的初始化操作。

    以下是关于一个Card类层次结构定义的一些例子。这里定义了一个基类和3个子类来描述Card类的基本信息。有两个变量是参数直接赋值的,另外两个参数是通过初始化方法计算来完成初始化的。

    class Card:
      def __init__( self, rank, suit ):
        self.suit= suit
        self.rank= rank
        self.hard, self.soft = self._points()
    class NumberCard( Card ):
      def _points( self ):
        return int(self.rank), int(self.rank)
    class AceCard( Card ):
      def _points( self ):
        return 1, 11
    class FaceCard( Card ):
      def _points( self ):
        return 10, 10

    在以上代码段中,__init()__把公共初始化方法引入到了基类Card中,这样3个子类NumberCard、AceCard和FaceCard都能够共享公共的初始化逻辑。

    这是一个常见的多态设计,每个子类为_points()方法提供特有的实现。所有的子类有相同的方法名和属性。这3个子类在使用时可以通过互换对象来更换实现方式。

    如果只是简单地使用字母来定义花色,就可以使用如下的代码段来创建Card对象。

    cards = [ AceCard('A', ''), NumberCard('2',''), NumberCard('3',''), ]

    这里枚举了Card集合中的几个Card对象,把牌面值(rank)和花色(suit)作为参数传入来实例化。从长远来看,需要一个更智能的工厂函数来创建Card对象,因为枚举所有52张牌非常麻烦而且容易出错。在介绍工厂函数前,先看一些其他的问题。

    展开全文
  • 以下简单示例演示了在基类中声明可从派生类引发的事件的标准方法。此模式广泛应用于 .NET Framework 类库的 Windows 窗体类。 创建可用作其他类的基类的类时,应考虑如下事实:事件是特殊类型的委托,只可以从...
  • 但是,有的CRUD操作却是类似的,可以通过Mybatis提供的注解加上反射实现传入实体类就是简单的CRUD操作,这样的实现是基于对单表的操作,需要进行关联查询等操作时,还是老老实实的写mapper文件。 一、Mybatis...

    项目中少不了CRUD的操作,在Mybatis中的Mapper文件中也随处可见增、删、改、查。但是,有的CRUD操作却是类似的,可以通过Mybatis提供的注解加上反射实现传入实体类就是简单的CRUD操作,这样的实现是基于对单表的操作,需要进行关联查询等操作时,还是老老实实的写在mapper文件中。

    一、Mybatis中的注解

    定义Mybatis基类我们需要用到org.apache.ibatis.annotations包下面四个很重要的注解:

    (1)@InsertProvider,提供插入的SQL语句

    (2)@DeleteProvider,提供删除的SQL语句

    (3)@UpdateProvider,提供修改的SQL语句

    (4)@SelectProvider,提供查询的SQL语句

    @SelectProvider注解的中定义了两个属性,其中,type:指定提供SQL语句的类;method:指定提供SQL语句的方法。其他三个注解中也都有这两个属性。通过这些注解,在Mapper接口中定义方法时,我们就可以利用它来指定为这个方法指定提供SQL语句的方法,也就是这些主要用在Mapper接口中的方法上。这里我们不深入介绍Mybatis是如何通过这个注解获取SQL语句的,有兴趣的朋友可以看这篇博客https://blog.csdn.net/u012734441/article/details/86285209

    @SelectProvider注解的源码如下:

    /**
     * @author Clinton Begin
     */
    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    public @interface SelectProvider {
      Class<?> type();
    
      String method();
    }

    二、定义Mybatis基类

    这里不介绍整过环境的搭建过程,下文中主要介绍定义基类中的主要过程,也就是怎么使用上述介绍的注解类来完成向Mapper提供SQL语句的过程,也就是下文中的第三步:完成提供SQL类的方法,第四步:利用注解定义基础类接口——BaseDao。

    第一,准备数据库表,表名为:user,字段定义如下:

    +---------+--------------+------+-----+---------+-------+
    | Field   | Type         | Null | Key | Default | Extra |
    +---------+--------------+------+-----+---------+-------+
    | id      | varchar(10)  | NO   | PRI | NULL    |       |
    | name    | varchar(20)  | YES  |     | NULL    |       |
    | gender  | varchar(1)   | YES  |     | NULL    |       |
    | age     | int(3)       | YES  | MUL | NULL    |       |
    | address | varchar(100) | YES  |     | NULL    |       |
    +---------+--------------+------+-----+---------+-------+

    第二,准备实体类。需要注意的是,通过主键查询时,需要告诉提供SQL的方法哪个属性是对应的主键字段,如果没有找到主键,也就是,在拼接SQL时无法指定WHERE条件,那么提供通过主键查询的方法会抛出异常。那么,我们需要怎样告诉提供SQL的方法,哪个是主键对应的属性呢?这里通过自定义注解的方式实现,自定义主键@Id,并实体中相应的字段上使用该注解,该表的主键就是id,所以需要在id属性上加上该注解,这样就等于告诉了提供SQL的方法id属性对应的列就为user表的主键。

    public class User {
    
    	@Id
    	private String id;
    	private String name;
    	private String gender;
    	private String age;
    	private String address;
    
    	// 省略get和set方法
    
    }

    第三,定义BaseProvider<T>类用于提供SQL语句,该类完成提供全部查询和通过主键查询的方法。分页查询也是同样的,将分页的参数传入拼接上即可,如果需要进行单表的条件查询,那么在解析属性的时候还需要对字段类型进行判断,以完成SQL语句的拼接。这里不演示添加、修改、删除,因为是同样的原理,不过是拼接SQL语句的过程不同而已。

    在拼接的方法中使用了StringBuilder类完成SQL语句拼接的工作,可能是平时工作的习惯导致的吧。实际上,可以使用Mybaits提供的SQL类完成拼接SQL的任务,而且SQL类提供了很多方便的API可帮助我们很好的解决问题。另外,这里的BaseProvider类中为了方便将通过实体解析的字段在了Map中。

    BaseProvider<T>类的代码如下:

    public class BaseProvider<T> {
        // 保存需要查询的字段和主键字段的名称
        private Map<String,String> fieldMap = new HashMap<String,String>();
        private static final String KEY_ID = "id";
        private static final String KEY_QUERY = "query";
    
        /**
         * 拼接查询语句
         *
         */
        public String provideQueryAllSql(Class<T> clazz){
            parseFields(clazz);
            StringBuilder sql = new StringBuilder();
            sql.append("SELECT ");
            sql.append(fieldMap.get(KEY_QUERY));
            sql.append(" FROM ");
            sql.append(getTableName(clazz.getSimpleName()));
            return sql.toString();
        }
    
        /**
         * 拼接通过主键查询的SQL
         *
         */
        public String provideQueryById(Class<T> clazz, Serializable id){
            StringBuilder sql = new StringBuilder(provideQueryAllSql(clazz));
            // 如果没有找到主键就抛出异常
            if (!fieldMap.containsKey(KEY_ID))
                throw new RuntimeException(clazz.getName()+":没有标识主键");
            sql.append(" WHERE ");
            sql.append(fieldMap.get(KEY_ID));
            sql.append("='" + id + "'");
            return sql.toString();
        }
    
        /**
         * 获取表名
         */
        private String getTableName(String className){
            // 将实体名称的首字母小写之后再转换
            char[] arr = className.toCharArray();
            arr[0] += 32;
            return parse(new String(arr));
        }
    
        /**
         * 将实体中的属性全部转换,并拼接为需要查询的字段
         *
         * @param clazz
         */
        private void parseFields(Class<T> clazz){
            StringBuilder columns = new StringBuilder();
            // 通过反射取到所有的属性
            Field[] declaredFields = clazz.getDeclaredFields();
            // 记录是否发现主键
            boolean unFoundedId = true;
            for (int i = 0,length = declaredFields.length; i < length; i++) {
                String filedName = declaredFields[i].getName();
                if(i == length - 1){
                    columns.append(parse(filedName));
                }else{
                    columns.append(parse(filedName) + ",");
                }
                // 如果找到主键之后,将不再执行以下代码
                if(unFoundedId){
                    Id annotation = declaredFields[i].getAnnotation(Id.class);
                    if(annotation != null){
                        fieldMap.put(KEY_ID,parse(filedName));
                    }
                    unFoundedId = true;
                }
            }
            // 将需要查询的字段保存到到map中
            fieldMap.put(KEY_QUERY,columns.toString());
        }
    
        /**
         * 驼峰命名转为带下划线的列名
         *
         */
        private String parse(String fieldName){
            StringBuilder columnName = new StringBuilder();
            for (int i = 0; i < fieldName.length(); i++) {
                char c = fieldName.charAt(i);
                // 如果是大写字母就加上下划线,并将其变为小写
                if(Character.isUpperCase(c)){
                    columnName.append("_").append(c += 32);
                }else{
                    columnName.append(c);
                }
            }
            return columnName.toString();
        }
    
    }

    第四、定义BaseDao接口使其继承BaseProvider<T>类,并定义查询全部和通过主键查询的方法,这样基础接口就算定义完成了,也就是当前定义的Mapper接口只要继承BaseDao接口就具备了查询全部和通过主键查询的功能。

    public interface BaseDao<T> {
        /**
         * 查询全部数据
         * @param clazz 实体类
         * @return
         */
        @SelectProvider(type = BaseProvider.class,method = "provideQueryAllSql")
        public List<T> queryAll(Class<T> clazz);
    
        /**
         * 通过主键查询
         *
         * @param clazz 实体类
         * @param id    主键值
         * @return
         */
        @SelectProvider(type = BaseProvider.class,method = "provideQueryById")
        public T queryById(Class<T> clazz, Serializable id);
    
    }

    第五、定义UserDao使其继承BaseDao接口,UserDao也就具有了查询全部和通过主键查询的功能。

    public interface UserDao extends BaseDao<User>{
        // 继承来自BaseDao的查询功能
    
    }

    接下来就可以进行测试了,测试类的代码和结果如下:

    public class Test {
    
        public static void main(String[] args) throws Exception {
            AnnotationConfigApplicationContext context =
                    new AnnotationConfigApplicationContext(AppConfig.class);
            UserDao userDao = context.getBean(UserDao.class);
            System.out.println(userDao.queryAll(User.class));
            //System.out.println(userDao.queryById(User.class,"1"));
    }

                                                                                  queryAll方法结果

     

                                                                                  queryById方法结果

    三、总结

    工作中,我们也会使用到类似的方法实现类似的功能,我们不仅需要会使用更需要知道它的实现原理,不然遇到一些非常的问题时就会无从下手。此外,面试中有的面试官也会提供这方面的问题。最后,定义Mybatis基类需要两方面的内容,一方面是Java反射相关的知识,另一方面为Mybatis注解。

    有不对的地方欢迎指正,希望对读者有所帮助!

    四、参考资料

    【1】https://blog.csdn.net/YingTao8/article/details/83116256——mybatis抽取基类BaseMapper(通用增/删/改/查)

    【2】https://blog.csdn.net/u012734441/article/details/86285209——MyBatis源码分析之@SelectProvider注解使用详解

     

    展开全文
  • C# 里面,接口的定义只...也就是在基类里面写好了方法,但继承接口,等子类继承接口的时候就需要子类实现方法。通过这样的方法可以在基类里面添加一些辅助方法,而这些方法默认给子类开启,除非子类继承了接口

    在 C# 里面,接口的定义只需要类里面存在和接口声明相同的方法或属性就可以,而存在的方法或属性是在子类定义的还是基类里面定义的都无所谓。也就是在基类里面写好了方法,但不继承接口,等子类继承接口的时候就不需要子类实现方法。通过这样的方法可以在基类里面添加一些辅助方法,而这些方法默认不给子类开启,除非子类继承了接口

    在基类定义的方法,如果在子类继承的接口里面声明的方法刚好和基类定义的相同,那么子类可以不需要再次定义。在基类可以判断当前自己的类型是否继承了接口

    这个方法用在基类里面期望在特定的代码里面给子类暴露一些内部的方法,但是又不能让子类随意调用。或者预设了一些方法,这些方法存在性能或其他的问题,只有子类声明自己需要这个功能的时候才被调用

    内部方法隐藏

    在基类里面有一些内部的方法,默认不让子类使用的,但只有某些特殊的子类的情况才能被使用。同时这些内部方法还可能被外部的其他方法调用,不一定是子类

    按照以上的约定就可以写出如下代码

        public interface ILindexiDb
        {
            string GetPrivateString();
        }
    
        public class BassClass
        {
            public string GetPrivateString()
            {
                if (!(this is ILindexiDb))
                {
                    throw new NotSupportedException("这个方法除非是林德熙逗比才能使用,其他人不能使用");
                }
    
                return "林德熙是逗比";
            }
        }
    

    从代码可以看到,除非这个类继承了 ILindexiDb 不然 GetPrivateString 方法将会异常,因为我期望这个方法只有我才能调用

    那么假如我有一个 Foo 的接口里面就需要使用到对应的方法,而默认业务想要返回的方法是基类定义的上面的方法

        public interface IFoo
        {
            void GetString();
        }
    
    

    不明真相的小伙伴可能会如何写?

        public class Foo : BassClass, IFoo
        {
            public void GetString()
            {
                Console.WriteLine(GetPrivateString());
            }
        }
    

    上面代码是小伙伴会直接写出的代码,然而这段代码没有运行的时候就会炸,原因是在基类判断当前这个类没有继承林德熙是逗比这个接口

    在我将基类放在一个程序集编译为dll之后,小伙伴没有方法直接看到源代码,他在调用 GetPrivateString 方法的时候抛出了方法没有支持异常,于是小伙伴会认为这个方法还没实现,她就不会想要去使用这个方法

    而林德熙逗比将会写出下面代码用来访问内部的方法

        public class Foo2 : BassClass, ILindexiDb, IFoo
        {
            public void GetString()
            {
                Console.WriteLine(GetPrivateString());
            }
        }
    

    因为注入的都是 IFoo 接口,小伙伴都不知道实际实现的 Foo2 里面做了什么,如果不信,请在 VisualStudio 里面用上代码,然后调试一下。此时很难知道 Foo2 里面做了什么魔法让调用 GetPrivateString 方法不会异常,因为在调试的时候是很难知道当前这个类继承了哪些接口,而一般调试的时候都不会注意到某个类继承的接口会影响到具体调用的方法

    我写了很多调试的方法,请看dotnet 代码调试方法

    引用子类方法

    按照这个约定,其实还可以让基类在满足一定条件的时候才能执行,这个条件需要子类定义。这个方法是上面说到的内部方法隐藏的升级,用起来将会更复杂

    在基类里面判断当前类是否继承了某个接口,如果继承了,那么将会可以调用接口的方法。这个方法一般用在某个接口的声明要用到很多基类的信息才能实现,或某个接口本身不适合在外部的其他类继承,只能由子类继承

    例如我定义了接口,用来判断林德熙是不是逗比的接口,而这个接口的方法实现需要依赖于基类的内容才能判断,但基类的内容是私有的,从业务上也不应该让外部方法知道

        public interface ILindexiConverter
        {
            bool CheckLindexiIsDoubi();
        }
    

    以下是基类的定义

        public class BassClass
        {
            protected string Name { get; } = "林德熙逗比";
    
            public string GetPrivateString()
            {
                // 忽略代码
            }
        }
    

    基类里面定义的 Name 属性是不能给外部类知道的,要不大家都知道我逗比,只有子类才能知道

    此时基类需要依赖 ILindexiConverter 的判断才能决定是否需要做业务

            public string GetPrivateString()
            {
                // 忽略代码
    
                    if (!lindexiConverter.CheckLindexiIsDoubi())
                    {
                        throw new NotSupportedException("这个方法除非是林德熙逗比才能使用,其他人不能使用");
                    }
    
            }
    

    然而 ILindexiConverter 接口除非是子类,其他类是无法按照预期做到的,于是在基类里面可以这样写

                if (this is ILindexiConverter lindexiConverter)
                {
                    if (!lindexiConverter.CheckLindexiIsDoubi())
                    {
                        throw new NotSupportedException("这个方法除非是林德熙逗比才能使用,其他人不能使用");
                    }
                }
    

    判断当前这个类是否有继承 ILindexiConverter 接口,如果有就调用方法,按照这个方式写小伙伴就更加不能简单调用这个方法

    而作为逗比我将会写出下面的代码,用于调用

        public class Foo2 : BassClass, ILindexiDb, IFoo, ILindexiConverter
        {
            public void GetString()
            {
                Console.WriteLine(GetPrivateString());
            }
    
            /// <inheritdoc />
            public bool CheckLindexiIsDoubi()
            {
                return base.Name == "林德熙逗比";
            }
        }
    

    我在 Foo2 里面的 CheckLindexiIsDoubi 用到基类的属性判断,同时基类因为子类继承了预期接口而能使用

    这就是通过在基类里面定义好方法和定义好代码逻辑,只要子类继承接口才能实现

    我搭建了自己的博客 https://blog.lindexi.com/ 欢迎大家访问,里面有很多新的博客。只有在我看到博客写成熟之后才会放在csdn或博客园,但是一旦发布了就不再更新

    如果在博客看到有任何不懂的,欢迎交流,我搭建了 dotnet 职业技术学院 欢迎大家加入

    知识共享许可协议
    本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。欢迎转载、使用、重新发布,但务必保留文章署名林德熙(包含链接:http://blog.csdn.net/lindexi_gd ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我联系

    展开全文
  • C++虚基类实现机制

    千次阅读 2015-03-02 09:33:03
    《深度探索C++对象模型》里,有一个问题,也是去公司面试的时候那些技术人员常问的问题:C++,obj是一个类的对象,p是指向obj的指针,该类里面有个数据成员mem,请问obj.mem和p->mem在实现和效率上有什么不同...

    在《深度探索C++对象模型》里,有一个问题,也是去公司面试的时候那些技术人员常问的问题:在C++中,obj是一个类的对象,p是指向obj的指针,该类里面有个数据成员mem,请问obj.mem和p->mem在实现和效率上有什么不同。
    答案是:只有一种情况下才有重大差异,该情况必须满足以下3个条件:

    (1)、obj 是一个虚拟继承的派生类的对象
    (2)、mem是从虚拟基类派生下来的成员
    (3)、p是基类类型的指针

    当这种情况下,p->mem会比obj.mem多了两个中间层。(也就是说在这种情况下,p->mem比obj.mem要明显的慢,呵呵)

    WHY?

    如果好奇心比较重的话,请往下看 :)


    1、虚基类的使用,和为多态而实现的虚函数不同,是为了解决多重继承的二义性问题。

    举例如下:

    class A
    {
    public:
        int a;
    };

    class B : virtual public A
    {
    public:
       int b;
    };

    class C :virtual public A
    {
    public:
       int c; 
    };

    class D : public B, public C
    {
    public:
       int d;
    };

    上面这种菱形的继承体系中,如果没有virtual继承,那么D中就有两个A的成员int a;继承下来,使用的时候,就会有很多二义性。而加了virtual继承,在D中就只有A的成员int a;的一份拷贝,该拷贝不是来自B,也不是来自C,而是一份单独的拷贝,那么,编译器是怎么实现的呢??

    在回答这个问题之前,先想一下,sizeof(A),sizeof(B),sizeof(C),sizeof(D)是多少?(在32位x86的linux2.6下面,或者在vc2005下面)

    在linux2.6下面,结果如下:sizeof(A) = 4; sizeof(B) = 12; sizeof(C) = 12; sizeof(D) = 24

    sizeof(B)为什么是12呢,那是因为多了一个指针(这一点和虚函数的实现一样),那个指针是干嘛的呢?

    那么sizeof(D)为什么是24呢?那是因为除了继承B中的b,C中的c,A中的a,和D自己的成员d之外,还继承了B,C多出来的2个指针(B和C分别有一个)。再强调一遍,D中的int a不是来自B也不是来自C,而是另外的一份从A直接靠过来的成员。

    如果声明了D的对象d: D d;
    那么d的内存布局如下:

    vb_ptr: 继承自B的指针
    int b: 继承自B公有成员
    vc_ptr:继承自C的指针
    int c: 继承自C的共有成员
    int d: D自己的公有成员
    int a: 继承自A的公有成员


    那么以下的用法会发生什么事呢?

    D dD;
    B *pb = &dD;
    pb->a;

    上面说过,dD中的int a不是继承自B的,也不是继承自C的,那么这个B中的pb->a又会怎么知道指向的是dD内存中的第六项呢?

    那就是指针vb_ptr的妙用了。原理如下:(其实g++3.4.3的实现更加复杂,我不知道是出于什么考虑,而我这里只说原理,所以把过程和内容简单化了)

    首先,vb_ptr指向一个整数的地址,里面放的整数是那个int a的距离dD开始处的位移(在这里vb_ptr指向的地址里面放的是20,以字节为单位)。编译器是这样做的:

    首先,找到vb_ptr(这个不用找,因为在g++中,vb_ptr就是B*中的第一项,呵呵),然后取得vb_ptr指向的地址的内容(这个例子是20),最后把这个内容与指针pb相加,就得到pb->a的地址了。

    所以说这种时候,用指针转换多了两个中间层才能找到基类的成员,而且是运行期间。

    由此也可以推知dD中的vb_ptr和vc_ptr的内容都是一样的,都是指向同一个地址,该地址就放20(在本例中)

    如下的语句呢:

    A *pa = &dD;
    pa->a = 4;

    这个语句不用转换了,因为编译器在编译期间就知道他把A中的成员插在dD中的那个地方了(在本例中是末尾),所以这个语句中的运行效率和dD.a是一样的(至少也是差不多的)

    这就是虚基类实现的基本原理。

    注意的是:那些指针的位置和基类成员在派生类成员中的内存布局是不确定的,也就是说标准里面没有规定int a必须要放在最后,只不过g++编译器的实现而已。c++标准大概只规定了这套机制的原理,至于具体的实现,比如各成员的排放顺序和优化,由各个编译器厂商自己定~
    展开全文
  • 《深度探索C++对象模型》里,有一个问题,也是去公司面试的时候那些技术人员常问的问题:C++,obj是一个类的对象,p是指向obj的指针,该类里面有个数据成员mem,请问obj.mem和p->mem在实现和效率上有什么不同...
  • C++,obj是一个类的对象,p是指向obj的指针,该类里面有个数据成员mem,请问obj.mem和p->mem在实现和效率上有什么不同。 答案是:只有一种情况下才有重大差异,该情况必须满足以下3个条件: (1)、obj 是一个...
  • 前者 表明基类中的函数被派生类函数覆盖了,它们几乎没有关联,C++就是两个完全不同的函数,只不过恰巧名字一样而已(但有不同的类作用域),就像不同的作用域定义了两个相同名字的变量。 int a; //类似基类中...
  • title author date CreateTime categories ... C# 在基类定义好方法让子类继承接口就能实现 lindexi 2019-07-29 09:57:49 +0800 2019-07-12 08:26:16 +0800 C# C# 里面,接口的定义只...
  • 1,从存储空间角度 虚函数对应一...所以构造函数不能是虚函数。 vtbl是编译期就建立了,各个虚函数这时被组织成了一个虚函数的入口地址的数组.而对象的隐藏成员--vptr是运行期--也就是构造函数被调用时进行初...
  • Python的单元测试框架unittest,以后我们所有的测试类文件,都采用unittest来辅助我们进行debug和脚本开发。搞定了debug机制和确定了unittest来进行创建和管理我们的自动化测试脚本,接下来我们来考虑下,框架设计...
  • c++虚基类在内存的分布

    千次阅读 2017-08-03 14:19:18
    今天重温C++的知识,当看到虚基类这点的时候,那时候也没有太过追究,就是知道虚基类是消除了类继承之间的二义性问题而已,可是很是好奇,它是怎么消除的...C++,obj是一个类的对象,p是指向obj的指针,该类里面有
  • If the author of the article is not allowed to reprint, this article will be deleted C++ - 虚基类、虚函数与纯虚函数: ...C++虚基类实现机制: https://blog.csdn.net/Hsuxu/art...
  • 抽象基类

    2013-05-24 17:20:48
    怎么的一个基类可以作为抽象基类呢?含有纯虚函数的基类是一个抽象基类。纯虚函数和虚函数的额区别是什么呢?... 在基类中使用纯虚函数意味着不在基类中进行具体的实现,而是强制各派生类进行具体的
  • 标题有点拗口难懂,用代码来说比较浅显,其实是要实现以下效果: class Base { // 基类中定义一个虚方法 ExecuteNonQuery,用以执行一段 SQL 查询,并传递一个参数 public virtual int ExecuteNonQuery(string ...
  • 《深度探索C++对象模型》里,有一个问题,也是去公司面试的时候那些技术人员常问的问题:C++,obj是一个类的对象,p是指向obj的指针,该类里面有个数据成员mem,请问obj.mem和p->mem在实现和效率上有...
  • 公用继承、私有继承和保护继承,只有公用继承较好地保留基类的特征,它保留了除构造函数和析构函数以外的基类所有成员,基类的公用或保护成员的访问权限派生类全部都按原样保留下来了,派生类外可以调用...
  • RTTI、虚函数和虚基类实现方式、开销分析及使用指导 白杨 http://baiy.cn   “正确的场合使用恰当的特性” 对称职的C++程序员来说是一个基本标准。想要做到这点,首先要了解语言每个特性的实现...
  • Singleton的一个基类实现

    千次阅读 2008-07-13 21:24:00
    创建型模式,有一种设计模式“Singleton”。该模式的意图是,保证一个类仅有一个实例,并提供一个访问它的全局访问点。GOF的指导下,我们经常写一些Singleton类。每个类很类似。 以下代码描述了一个Singleton...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 129,468
精华内容 51,787
关键字:

以下不能在基类中实现的是