您的位置:首页 > 编程语言 > C语言/C++

C++ 中的一些小问题, 持续补充

2012-03-28 01:07 351 查看
C++ Primer Plus 205

char *buildstr(char c,int n)
{
char* pstr = new char[n + 1]
pstr
= '\n';
while(n-- > 0)
pstr
= c;
return pstr;
}

int  main
{
int times;
char ch;
char *ps = buildstr(ch,times);
delete [] ps;
}


因为在 buildstr 函数中的 pstr 是局部函数 ,所以当函数结束时 pstr 被释放, 在main函数中, ps仍然指向 buildstr中的返回值 ,但是当使用完ps後 需要釋放ps,尽管之前没有在main函数中new过。

2.#include <iostream>

class B
{
public:
virtual int shift(int n = 2) const { return n << 2; }
};

class D
: public B
{
public:
int shift(int n = 3) const { return n << 3; }
};

int main()
{
const D d;
const B *b = &d;

std::cout << b->shift() << std::endl;

return 0;
}


输出结果为16  虚函数为动态绑定的,但是当有默认参数时,编译器为了省去动态绑定默认值的低效而采用了静态绑定 即 采用基类的默认参数。

3.一个函数指针的例子

C++ Primer Plus 218
double betsy(int)
double pam(int)
//声明时可以省略 参数名

double betsy(int lns)
{
return 0.05 * lns;
}

double pam(int lns)
{
return 0.03 * lns + 0.0004 * lns * lns;
}

void estimate(int lines , double(*pf)(int))
{
cout << lines << "lines will take"
cout << (*pf)(lines) << " hours\n";
}

void main()
{
estimate(code , betsy);
estimate(code , pam);
}


用括号括起来 *pf 是函数 pf是指向函数的指针。

内联函数比常规函数少块, 但是占据更多的代码空间,因为内联函数可以省去函数跳转到其他函数这个操作步骤,但是取而代之的是复制函数的拷贝到每个需要使用这个函数的函数的地址附近。(编译过程中扩展代码)

所以需要考虑 跳转和执行代码的比率,来判断使用内联函数获得的时间上的收益。

4.引用 

int rats

int &rodents = rats

则 rodents 为rats的别名 他们指向同一个内存地址。

在初始化rodents的时候就必须绑定他的值 并且以后不再能改变绑定的对象

int & rodents = rats

等价于

int * const rodents = &rats;

inline const syosp & use (syosp & sysopref)
{
sysopref.used++;
syosp test = sysopref;
//return sysopref;
return test;
}

int main()
{
syosp looper =
{
"test",
"testtest",
0
};
syosp ref;
ref = use(looper);
cout << ref.name << ref.quote << ref.used << endl;
getchar();
}


当引用作为返回值时将直接返回返回值 而不是再把返回值拷贝到零时变量中。

值得注意的是,当返回值为函数中的局部变量时,外部调用的函数仍能成功访问.

或许是VS编译器的问题,这样的情况应当是被避免的。

当返回值为引用时,最好的办法是返回一个作为参数传递给函数的引用。

另外一个办法是 你可以在函数中new一个新的对象出来。但是就和第一例讲到的一样,你必须记得在外部delete他们。

   b.   Pointers   to   const   objects   cannot   be   deallocated   with   the   

          delete   operator.   (delete   operator   in   MSDN). 

    c.   Q1:   const   int*   pInt   =   new   int(0);   //指向常量的指针 

                  delete   pInt;    //error,看上一条b. 

5.
#include <iostream>

template<unsigned N>
class A
{
public:
A() { std::cout << N; }

private:
A<N - 1> m_a;
};

template<>
class A<0>
{
public:
A() { std::cout << 'A'; }
};

int main()
{
{ A<4>(); }

std::cout << std::endl;

return 0;
}


template 模板递归实现。自底向上。 。。

6
.#include <iostream>

class A
{
public:
explicit A(int n = 0) : m_n(n) { }

A(const A& a)
: m_n(a.m_n)
{
++m_copy_ctor_calls;
}

public:
static int m_copy_ctor_calls;

private:
int m_n;
};

int A::m_copy_ctor_calls = 0;

A f(const A& a) { return a; }

A g(const A a) { return a; }

int main()
{
A a;
A b = a, c(a); // 1
std::cout << A::m_copy_ctor_calls;

b = g(c); //2
std::cout << A::m_copy_ctor_calls;

const A& d = f(c); // 3
std::cout << A::m_copy_ctor_calls << std::endl;
getchar();
return 0;
}


输出结果为 245   

1中 当 a 赋值给 b时候 b由于新分配内存空间 调用一次拷贝构造函数 c 的初始化调用一次 当c再赋值给b 是 调用的应该是 运算符 = 的重载

2中 参数传递拷贝一次, 返回值传递一次

3中 返回值调用一次

7
.#include <iostream>
#include <vector>

class A
{
public:
A(int n = 0) : m_n(n) { }

public:
virtual int value() const { return m_n; }
virtual ~A() { }

protected:
int m_n;
};

class B
: public A
{
public:
B(int n = 0) : A(n) { }

public:
virtual int value() const { return m_n + 1; }
};

int main()
{
const A a(1);
const B b(3);
const A *x[2] = { &a, &b };
typedef std::vector<A> V;
V y;
y.push_back(a);
y.push_back(b);
V::const_iterator i = y.begin();

std::cout << x[0]->value() << x[1]->value()
<< i->value() << (i + 1)->value() << std::endl;

return 0;
}


输出结果1413 

数组X中保存的是对象的地址 在调用数组中的类型的时候会根据RTTI动态找到对象的函数

但是VECTOR容器中保存的是 父类对象A的元素 因为VECTOR是连续的内存地址, 他会把子类自动转成基类以便能封装进VECTOR中

8.
#include <iostream>

class A
{
public:
A(int n = 2) : m_i(n) { }

~A() { std::cout << m_i; }

protected:
int m_i;
};

class B
: public A
{
public:
B(int n) : m_x(m_i + 1) , m_a(n) { }

public:
~B()
{
std::cout << m_i;
--m_i;
}

private:
A m_x;
A m_a;
};

int main()
{
{ B b(5); }

std::cout << std::endl;

return 0;
}


输出结果为2531  先调用b的析构函数 然后再释放B的成员变量再调用父类的析构函数

虚函数表在类地址的最开始。

operator int () const重载类转换运算符号

比如 

C c;

int  a = (int)c;

9
.#include <iostream>
#include <vector>

class A
{
public:
A(int n) : m_n(n) { }
A(const A &a) : m_n(a.m_n) { ++m_copy_ctor_calls; }
~A() { ++m_dtor_calls; }

private:
int m_n;

public:
static int m_copy_ctor_calls;
static int m_dtor_calls;
};

int A::m_copy_ctor_calls = 0;
int A::m_dtor_calls = 0;

int main()
{
const A a = 2;//1
std::vector<A> v;
v.reserve(2);
4000
v.push_back(a);
v.push_back(1);//2
v.push_back(a);//3
std::cout << A::m_copy_ctor_calls << A::m_dtor_calls << std::endl;
getchar();
return 0;
}


输出结果为 5 3

运行到1时 调用构造函数不是拷贝构造函数

运行到2时 创建一个临时对象调用拷贝构造函数然后释放临时对象

3时容量不够 创建新的内存空间 复制旧的到新的 释放旧的 

10. static const,virtual
class test
{
static fun() const {}
static virtual gun() {}
};


如果使用 是成员函数 如果使用 static 描述的 话,则不能同时为const 或者 virtual 因为,const 和 virtual内部包含了一个隐含的this指针。

未完待续..
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息