Chinaunix首页 | 论坛 | 博客
  • 博客访问: 111855
  • 博文数量: 17
  • 博客积分: 1430
  • 博客等级: 上尉
  • 技术积分: 200
  • 用 户 组: 普通用户
  • 注册时间: 2008-08-13 12:10
文章分类
文章存档

2010年(1)

2009年(5)

2008年(11)

我的朋友

分类: C/C++

2009-12-29 15:06:46

@1、所有对象(虽然具有唯一性)都是一类对象中的一员,它们有共同的特征和行为。每个类的一员都有共性,如每个账户都有余额,每个账户都可以被查询,同时,每个成员都有自己的状态(个性
),每个账户余额有不同的金额。每个账户(对象)是账户类的一个实例,每个对象都属于一个定义了它的特性和行为的特定类。
两层分类:
第一层,是属于同一基类的派生类,基类代表了它们共同的特征和行为,而每个派生类又有自己特有的特征和行为;
第二层,一个类的不同实例,它们具有相同的属性,但是属性状态可能各不相同。成员数据可以不相同,成员方法也可以通过行为类来做到不同。
class test {
    state s;
    handler h; //或vector hv; 实现注册多个行为,使类对象具有添加删除修改行为数量的能力
    //handler1 h1; handler2 h2; 也可以让对象具有固定的几个行为,但是行为可以动态确定
public:
    void behavior(int action); // h.act();
};
@2、每个对象只能满足特定的请求。可以向对象发出的请求是由它的接口定义的,而接口由类型确定。
@3、类创建者的目标是去创建类,这个类只暴露对于客户程序员是必需的东西,其他的都隐藏起来。这样,这个类的创建者可以改变隐藏的部分,而不用担心会影响其他人,另外,被隐藏的部分通常
是对象内部的管理功能,隐藏实现会减少程序错误。将接口从实现中分离出来。
@4、头文件是我们和我们的库的用户之间的合约。这份合约描述了我们的数据结构,为函数调用规定了参数和返回值。
@5、不要将using namespace name;放入头文件,这样指令会在所有引用此头文件的地方去除对name命名空间的保护。
@6、嵌套友元的方法
class ctest {
public:
    class cfriend;   //声明友元类
    friend cfriend;  //设置友元
    class cfriend {  //定义友元类
    };
};
@7、在程序运行期间,对象变成了一个存储区域,如果有人真的想破坏C++隐藏机制,直接访问内存中的数据,就如C中所做的那样,那么C++并不能防止他做这种不明智的事。
@8、用goto语句跳出程序块,程序块中的对象的析构函数仍会被调用,但是如果是非局域的跳转(如setjmp()和longjmp组合)就可能不会引发析构函数的调用了。
@9、局部变量定义时要注意,不能存在可能在作用域内被跳过的构造函数调用
class X {
public:
    X();
};
X::X() {}
void f(int i) {
    if (i < 10) {
        // goto jump; // Error: goto bypasses init
    }
    X x1;  //作用域为f(),构造函数可能被goto跳过
jump:
    switch (i) {
        case 1: //{
            X x2;  //作用域为switch(),构造函数可能被case2跳过,加上括号后,作用域为case1就不会发生这种错误了
            break;
        //}
        //case 2: //{  //Error: goto bypasses init
            X x3;
            break;
        //}
    }
}
@10、如果struct中有私有成员,或有构造函数,构造函数必须被调用来完成初始化,不能使用{成员1值,成员2值, ...}方式初始化
struct X {
    int i;
    X(int a = 0);
};
X x[3] = {X(1), X(2)}; //x[3]使用X()默认构造函数初始化!
其他情况可以:
struct Y {
    int a;
    int b;
};
Y y[3] = { {1, 2}, {1, 3} };  //第三个对象被初始化为0! 类似int a[2] = {1} a[0] = 1 a[1] = 0
@11、C++中的const默认为内部连接,const仅在定义过的文件里才是可见的,而在连接时不能被其他编译单元看到。所以把const变量放在头文件中不会发生冲突。const变量在定义时必须赋初值。
而C中的const就是个不能被改变值的变量。
@12、必须在static const定义的地方对它进行初始化
class X {
    static const int a = 100;
    enum { b = 100 };  //b和a作用相同,也是常量,并且不占用对象的存储空间,类似于宏,在编译时得到枚举值,在类外使用需加域作用域符,X::b,类内使用不用这样
};
 
类中命名枚举使用方法:
class X {
public:
    enum Status { UP = 1, DOWN = 0 };
}
 
X::Status s = X::UP;
 
@13、const成员函数在声明和定义时到要使用const关键字!这也是函数重载的一种方式
class X {
    int f() const;
};
int X::f() const { return 0; }
@14、使用mutable指定一个const对象中可以修改的数据成员。
class X {
public:
    int x;
    mutable int y;
};
const X x;
//x.x++;  //不可以
x.y++; //OK
@15、volatile对象只能被volatile成员函数调用,就像const对象。
@16、类声明时定义的函数都会成为内联函数,有时可能会造成占用内存过多。如需将函数定义为内联,最好是在类外定义,使用inline指明。
@17、三种使用命名空间优先级:最高优先级是作用域运算符::,其次是使用using声明类型,最低是using引用命名空间
namespace U {
    void f() {}
}
namespace V {
    void f() {}
}
int main() {
    using namespace U;
    using V::f();
    f();  //调用V::f()
    U::f(); //调用U::f()   
}
@18、对于所有的临时对象,必须假设他们是不可存取的。
@19、指向成员数据的指针,指向成员方法的指针
定义时说明指向成员,使用时说明使用对象(或其指针),其他就是比普通指针在声明时多了类域,赋值时成员前也必须带类域(无论在类内,还是类外)
class X {
    int a;
    int f() const;
};
int X::f() const {
}
int X::pmInt;
pmInt= &X::a;
int (X::*pmf)() const;
pmf = &X::f;  //必须带&,不像全局函数那样可选
X x;
X *px = &x;
px->*pmInt = 10;
x.*pmInt = 10;
(px->*pmf)();
(x.*pmf)();
@20、运算符重载
所有一元运算符、赋值=,+=等,(),[],->,->*都作为成员函数,所有其他二元运算符都作为非成员函数
返回外部变量(或*this)使用引用,返回临时变量返回对象
不能重载.和.*
class test {
const test& operator+() const;  //+test
const test operator-() const;   //-test
const test operator~() const;   //~test
test operator!() const;    //!test
test* operator&();         //&test
const test& operator++();  //++test
const test operator++(int);  //test++
const test& operator--();   //--test
const test operator--(int);  //test--
返回类型 operator*();   //*test
test& operator=(const test &r); //test = r
test& operator+=(const test &r); //test += r
 
类型& operator[] (int index);   //test[index]
指针指向类型* operator->() const; //test->
返回值类型 operator()(参数列表); //test()  是否为const要根据被使用情况
返回类重载了() operator->*(指向成员函数的指针类型);
};
friend const test operator+(const test& l, const test& r); //l + r

friend int operator ==(const test &l, const test &r);  //返回0或非0,l == r

ostream& operator<<(ostream &os, const test &r);  //os << test
istream& operator>>(istream &is, const test &r);  //is >> test
@21、赋值运算符重载一定注意自赋值检查,防止a = a操作造成内存泄漏等问题
@22、自动类型转换,两种类型:
第一种 特殊类型的构造函数
class One {
public:
    One() {}
};
class Two {
public:
    Two(const One&) {}
};
void f(Two) {}
One one;
f(one);  //可以编译通过,调用Two(one)
将Two(const One&)设为显式类型转换,explicit Two(const One&)可以防止隐式自动类型转换
//f(one);  //编译不过
f(Two(one));  //ok
第二种 重载类型转换运算符
class One {
    int i;
public:
    One(int a=0):i(a) {}
    operator Two() const {return Two(i);}   //这个函数不需返回类型--返回类型就是正在重载的运算符的名字
};
class Two {
    int x;
public:
    Two(int a=0):x(a) {}
};
One one;
f(one);   //可以编译通过,调用operator Two()   
备注:
两种方法不能一起使用,容易混淆;基本类型(int,char*等)转换使用重载运算符,其他转换使用显式构造函数。
@23、delete一个void*指针,只释放内存
@24、new耗尽内存会调用new_handler函数,这个函数的默认动作是抛出bad_alloc异常。可以使用set_new_handler(void (*func)())修改处理函数
@25、重载operator new()和operator delete(),只是改变了原有的内存分配方法。不会影响构造函数和析构函数的调用,虚表的建立是编译器加到构造函数前的,也不会受影响。new只需分配内存,
不用考虑初始化,由构造函数来初始化。
void *operator new(size_t sz) throw(bad_alloc); //size_t参数是由编译器传给new的,sizeof(类型)
void operator delete(void* p);
type *p = new type; //调用new
delete(p);          //调用delete
void *operator new[](size_t sz) throw(bad_alloc); //sz大小为数组整个的大小,sizeof(类型)*n
void operator delete[](void *p);
@26、继承默认是私有的,class derived : base等同于class derived : private base
@27、对于子对象(或基类)调用构造函数,使用构造函数的初始化表达式表,基类名(构造函数参数),子对象名(子对象类型构造函数参数),基本类型变量(基本类型参数)
如果不显式调用子对象的构造函数,编译器将自动调用该变量的默认构造函数,如果没有将报错。
@28、构造函数调用顺序:先基类,后派生类;先按子对象声明顺序调用子对象构造函数,后调用自己的构造函数。
@29、如果派生类重新定义了基类中的一个重载成员函数,则在派生类中其他的重载函数都将会被隐藏,但可以在派生类函数里使用base::来调用它们。
@30、构造函数,析构函数,operator=不能够被继承,不定义这些函数,编译器会自动生成它们。
@31、组合通常是在希望新类内部具有已存在类的功能时使用,而不是希望已存在类作为它的接口。has-a关系用组合表达,is-a关系用继承表达。
@32、私有继承创建的新类具有基类的所有数据和功能,但这些功能是隐藏的,如果想暴露一些基类的接口,可以使用using指出
class base {
public:
    void func ();
};
class derived : private base {
public:
    using base::func();
};
derived d;
d.func();  //ok
@33、保护继承创建的新类,基类的public成员对于它是public的,但对于外部则是私有的。
class base
{
public:
    value(int i) const { return i; }
};
class derived : protected base
{
public:
    int getvalue()
    {
        return value(1);
    }
};
derived d;
d.getvalue(); //ok
//d.value(1);  //编译错误
protected继承不能用于多态,不能通过基类指针访问派生类重写的函数。
@34、拷贝构造函数的调用顺序是和构造函数一样的,先基类(向上类型转换),后派生类,先子对象,后自己
Child(const Child &c) : Parent(c), 子对象初始化  //调用Parent(const Parent &p)
{
}
@35、仅需要在基类中声明一个函数为virtual,虽然也可以在派生类声明前使用virtual,但这样会使程序显得冗余和混乱。
@36、如果派生类没有重写基类的virtual函数,则会使用继承层次中最近的定义。
@37、每当创建一个包含有虚函数的类或从包含有虚函数的类派生一个类时,编译器就为这个类创建一个唯一的VTABLE,在这个表中,编译器放置了在这个类中或在它的基类中所有已声明为virtual函
数的地址。如果在这个派生类中没有对在基类中声明为virtual函数进行重新定义,编译器就使用基类这个虚函数的地址。
@38、编译器创建的默认构造函数,只做初始化VPTR的工作。
@39、纯虚函数也可以有定义。
@40、使用基类指针指向派生类,只能调用基类的函数。向下转换要小心,需使用dynamic_cast<>(),检查空指针。
@41、重新定义基类虚函数时,注意与普通函数不同,不能改变虚函数的返回值类型,因为编译器无法判断调用什么。隐藏机制同普通函数@29。
@42、在带有虚函数的类中,不要使用内联构造函数。
@43、使用多态,则使用虚拟析构函数。
@44、virtual运算符重载,因为都可能是使用基类指针访问,所以可能对不知道类型的对象进行操作,实现virtual运算符通常会很复杂。见p383
@45、关于模板的参数类型,模板为C++提供了一种弱类型机制,弱类型不是坚持一个类型是某个可接受的确切类型,而是只要求它想调用的成员函数对于一个特定对象可用就行了,可用就是说对象的
类中有模板要用到的接口。
@46、迭代器对它的使用者隐藏了类的底层结构。从一个容器元素移动到下一个元素的复杂过程被抽象为就像一个指针一样。目标是使程序中的每个迭代器都有相同的接口,使得使用这个迭代器的任何
代码都不用关心它所指向什么,只需知道它能用同样的方法重新配置所有的迭代器,也就是说这个迭代器所指向的容器并不重要了。
 
1、fstream
bool getline(const ifstream &in, string &s)
等同于
in >> s   //将in读入内容,输出到s
2、vector
push_back(E &e)
insert()
push_front()
3、构造函数的初始化顺序
在一个类里建立一个普通的(非static的)const时,不能给它初值。这个初始化工作必须在构造函数的初始化列表里进行。因此,对于这个常量,每个不同的对象可以有不同的常量值。
如果希望所有的对象此常量值都相同,需要使用static const。0
class testbase
{
    testbase()
};
class test : public testbase
{
    const int a;
public:
   
    test()
};
test::test(int var) : a(var)
{
}
初始化列表先于构造函数
4、函数返回值的生命期
test test::returntempobj()
{
    return test();  //这种函数返回被使用会产生临时对象
}
const test &ref = returntempobj();  //1 不要用ref,因为函数返回的临时对象的生命只维持到调用该函数的表达式结束为止。
test obj = returntempobj();   //2 ok

6、、临时对象
1)返回值返回一个对象,但是不处理这个返回值 p254
2) 方法参数为对象引用,但是传入参数需要强转?extern f(const string &s);  f("hello"); extern g(const int &i); g(1);
 
7、默认构造函数、默认拷贝构造函数
有了自己的拷贝构造函数,就要在有一个自己的默认构造函数
 
阅读(1128) | 评论(0) | 转发(0) |
0

上一篇:c++运算符优先级

下一篇:设计模式

给主人留下些什么吧!~~