随笔 - 55  文章 - 15  trackbacks - 0
<2024年11月>
272829303112
3456789
10111213141516
17181920212223
24252627282930
1234567

常用链接

留言簿

随笔分类

随笔档案

搜索

  •  

最新评论

阅读排行榜

评论排行榜

     摘要: MVVM的目的是为了把表现与逻辑分开来,相互之间不要有太大的影响,让程序员能够专心地做某一块。但有些时候必须要有联系,外部传入数据,控件接收数据,并传入后台处理,后台处理后的数据又要显示在控件上,这就需要数据绑定。数据绑定的方法已经说了几遍了,有3种方法,一种是源和目标都是依赖属性的时候,直接在Xaml文件中binding就行了,方法也比较简单;第二种和第三种方法针对的都是源不是依赖属性的时候,但目标必须是依赖属性,这时第二种方法要使用INotifyPropertyChanged接口,当属性改变的时候,一个Event被激活,并且提醒Binding对象将新值写入目标数据;第三种方法是设置DataContext,这种方法最简单,只需要在Xaml文件中设置一下就好。  阅读全文
posted @ 2012-06-26 17:24 Dino-Tech 阅读(1396) | 评论 (0)编辑 收藏
     摘要: windows 8 基本概念  阅读全文
posted @ 2012-06-12 18:43 Dino-Tech 阅读(595) | 评论 (1)编辑 收藏


#include <iostream>
using namespace std;
template<typename t>
t maximum(t a, t b){
    cout << "template" << endl;
    return a>b?a:b;
}

template<>
const char* maximum(const char* a, const char* b){
    return strlen(a) > strlen(b)? a:b;
}

//template<>
//char* maximum(char* a, char* b){
//    return strlen(a) > strlen(b)? a:b;
//}//如果没有const 的话,依旧会调用最上面的模板,因为编译器不能准确匹配,所以必须为const才行。

int main(){
    cout << maximum("pfdsfasdakis", "kadf") << endl;
}



#include <iostream>
using namespace std;

template<typename T>
class TestClass{
public:
    void F(T pT){
        cout << " T version " << endl;
        cout << pT << endl;
    }
};


template<>
class TestClass<int>{
public:
    void F(int pT){
        cout << "int version " << endl;
        cout << pT << endl;
    }
    void F(char pT){
        cout << "int version " << endl;
        cout << pT << endl;
    }如果这里修改成接受char型的参数,并且在main函数中调用obj2.F('a'),同样的,会调到该函数,所以说,编译器是在看到“TestClass<int> obj2;“这句的时候就知道该调用哪个了。
    void g(){}
};//特化的类在编译器中已经跟原来的类名字不同了,所以是两个东西,但是编译器要找一个最符合的名字。TestClass_int 可以在里面修改东西

int main(){
    TestClass<char> obj1;
    TestClass<int> obj2;
    obj1.F('A');
    obj2.F(10);
    obj2.g();
    return 0;
}

posted @ 2012-06-04 19:57 Dino-Tech 阅读(321) | 评论 (0)编辑 收藏
一个函数接受一个基类的指针或者引用,传入一个子类的指针或者引用(向上类型转换),希望调用子类的相应函数。目的:以后添加新的子类,都可以传入该函数。
早绑定:编译器通过上下文,判断该函数属于哪个对象,并在编译期将函数名与函数地址绑定。
晚绑定:在运行的时候,判断该函数属于哪个对象,并在运行时将函数名与函数地址绑定。必须有类型信息装在对象自身中。
声明时添加virtual关键字,定义时不需要。

使用指针和引用的目的是让编译器不能完全知道该对象的确切类型,不然就会调用早绑定。晚绑定是根据VTABLE来实现,并且基类和子类的每个虚函数的排列顺序都是相同的,所以调用函数的时候已经不是通过名字来调用,而是通过指令,通过函数地址的偏移量来调用了。

抽象基类的意义,为子类提供一个公共的接口。

通过基类指针调用基类中不存在的函数是危险的,因为,也许你恰好知道子类对象中有这个函数,那你的调用时成功的,但是万一木有呢?
class Base(){
public:
 virtual void f(){}
};

class Derived1: public Base
{
public:
 virtual void f(){}
 virtual void g(){}
};
class Derived2: public Base
{
public:
 virtual void f(){}
 virtual void m(){}
};

void func(Base* b){
b->g();
}
int main{
Base*Test1 = new Derived1;
Base*Test2 = new Derived2;
func(Test1);// right;
func(Test2);// crash
}

这里涉及到运行时类型识别(RTTI)和向下类型转换问题。向下类型转换不安全,因为没有类型信息,基类指针不知道基类的内存块之后的东西是属于哪个子类的,如果转错,将会比较麻烦。

在编程时注意防止对象的切片,如果按传值方式而不是传址和传引用方式
将子类对象传入一个接受基类对象的函数中去的话,那么,只拷贝子类对象中基类的部分数据,又因为编译器能明确地知道该对象的类型,所以不会产生晚绑定,而是早绑定。我们应该避免在这种情况下传值。

如果重新定义了基类中的虚函数,则基类中其他重载版本将被隐藏。(同非虚函数一样)
如果重载了基类中的虚函数,则基类中其他版本将被隐藏(同非虚函数一样)
不能在子类中修改基类中虚函数的返回值(非虚函数可以修改返回值,并且隐藏其他重载版本)
但是,也有特例
class PetFood{
public:
  virtual string foodType() const = 0;
};

class Pet{
public:
  virtual string type() const = 0;
  virtual PetFood* eat() = 0;
};

class Bird : public Pet{
public:
  string type()const {return "bird";}
  class BirdFood  :  public PetFood{
    public:
      string foodType()const{
         return "Bird food";
       }
     };
   PetFood* eat(){ return &bf;}
private:
   BirdFood bf;
};

class Cat: public Pet{
public:
  string type()const {return "cat";}
  class CatFood  :  public PetFood{
    public:
      string foodType()const{
         return "Cat food";
       }
     };
   CatFood* eat(){ return &cf;}// Here, you can return a CatFood*, because it's a PetType* type. Why don't return a type as PetFood? See segment in main()
private:
   CatFood cf;
};

int main(){
 Bird b;
 Cat c;
 Cat::CatFood* cf = c.eat();
 Bird::BirdFood* bf = b.eat();//downcast, warning!!!Cast PetFood* to BirdFood. So you better return a special pointer, not a base type.
}
}
返回确切的类型要更通用些。

vptr vtable由谁来初始化?构造函数?是编译器插入一小段代码在构造函数中初始化。
派生类只访问它自己的成员,而不访问基类的成员。只有基类的构造函数才能正确地初始化自己的成员。所以要在构造函数中:子要可能,我们应该在这个构造函数初始化列表中从初始化所有的成员对象(通过组合置于类中),因为你必须保证所有的东西都被初始化了,才能使用该对象。

在构造函数中调用虚函数,调用的只是本地版本。
原因:该对象还未初始完毕,但是vptr已经初始化,而且指向自己的vtable,所以调用的只是本地的函数。


1
posted @ 2012-06-04 16:27 Dino-Tech 阅读(236) | 评论 (0)编辑 收藏
     摘要: 代码重用的手段,利用已有的类。
组合:类似于使用工具,现有的类作为子对象。砍树:斧头作为子对象
继承:类似于学习本领,现有的类作为师父。砍树:拜师练习砍树的本领。  阅读全文
posted @ 2012-06-04 14:37 Dino-Tech 阅读(199) | 评论 (0)编辑 收藏
     摘要: 重载运算符,是STL的基础。  阅读全文
posted @ 2012-06-01 16:48 Dino-Tech 阅读(266) | 评论 (0)编辑 收藏
     摘要: 引用必须和一个存储单元联系起来;传值的时候会使用拷贝构造函数,为了防止位拷贝,最好自己写拷贝构造函数。为了防止传值,使拷贝构造函数为私有的,这里有个例子ostream os,不能这么写,必须传递引用 ostream& os。  阅读全文
posted @ 2012-05-31 17:01 Dino-Tech 阅读(185) | 评论 (0)编辑 收藏
     摘要: static 的各种应用。  阅读全文
posted @ 2012-05-31 14:30 Dino-Tech 阅读(135) | 评论 (0)编辑 收藏
     摘要: 编译器处理内联函数的策略。  阅读全文
posted @ 2012-05-30 16:45 Dino-Tech 阅读(240) | 评论 (0)编辑 收藏
     摘要: 内部链接,成员函数,常量表达式,传参和返回值,类里面的const  阅读全文
posted @ 2012-05-30 16:12 Dino-Tech 阅读(162) | 评论 (0)编辑 收藏
仅列出标题
共6页: 1 2 3 4 5 6