1.删除array中所有的6(迭代器失效问题)
#include <iostream>
#include <vector>
using namespace std;
void print(vector<int>);
int main()
{
vector<int> array;
array.push_back(1);
array.push_back(6);
array.push_back(6);
array.push_back(3);
vector<int>::iterator itor;
for(itor=array.begin();itor!=array.end();itor++)
{
if(*itor == 6)
{
// version 1:
array.erase(itor);
itor--;
// version 2:
//itor=array.erase(itor);
//itor--;
}
}
print(array);
return 0;
}
void print(vector<int> v)
{
cout<<"\n vector size is: "<<v.size()<<endl;
for(vector<int>::iterator i=v.begin();i!=v.end();i++)
cout<<*i<<endl;
}
2.指出下面程序的错误,如果把静态成员数据设为私有,该如何访问?
#include <iostream>
using namespace std;
class Cat
{
public:
Cat(int age):itsAge(age)
{
HowManyCats++;
}
virtual ~Cat()
{
HowManyCats--;
}
virtual int GetAge()
{
return itsAge;
}
virtual void SetAge(int age)
{
itsAge=age;
}
static int HowManyCats; //静态成员变量
private:
int itsAge;
};
//int Cat::HowManyCats=0; //需给静态成员变量赋初值
int main()
{
const int MaxCats=5;
int i;
Cat *CatHouse[MaxCats];
for(i=0;i<MaxCats;i++)
CatHouse[i]=new Cat(i);
for(i=0;i<MaxCats;i++)
{
cout<<"There are ";
cout<<Cat::HowManyCats;
cout<<" cats left!\n";
cout<<"Deleting the one which is ";
cout<<CatHouse[i]->GetAge();
cout<<" years old\n";
delete CatHouse[i];
CatHouse[i]=0;
}
return 0;
}
答案:该程序错在设定了静态成员变量,却没有给静态成员变量赋初值。可以在源程序的基础上添加赋值语句:int Cat::HowManyCats=0;程序结果为:
如果把静态成员数据设为私有,则1,可以通过公有成员函数访问(前提是访问时需要通过构造好的对象来使用公有成员函数)。2,通过公有静态成员函数访问(可以直接通过类使用公有静态成员函数)。方法一如下:
#include <iostream>
using namespace std;
class Cat
{
public:
Cat(int age):itsAge(age)
{
HowManyCats++;
}
virtual ~Cat()
{
HowManyCats--;
}
virtual int GetAge()
{
return itsAge;
}
virtual void SetAge(int age)
{
itsAge=age;
}
int GetHowMany()
{
//return HowManyCats;
cout<<"There are "<<HowManyCats<<" Cats alive!\n";
}
private:
int itsAge;
static int HowManyCats;
};
int Cat::HowManyCats=0;
int main()
{
const int MaxCats=5;
int i;
Cat *CatHouse[MaxCats];
for(i=0;i<MaxCats;i++)
{
CatHouse[i]=new Cat(i);
CatHouse[i]->GetHowMany();
}
for(i=0;i<MaxCats;i++)
{
delete CatHouse[i];
CatHouse[i]->GetHowMany();
}
return 0;
}
方法二中增添了函数count()调用公有静态成员函数GetHowMany(),方法二如下:
#include <iostream>
using namespace std;
class Cat
{
public:
Cat(int age):itsAge(age)
{
HowManyCats++;
}
virtual ~Cat()
{
HowManyCats--;
}
virtual int GetAge()
{
return itsAge;
}
virtual void SetAge(int age)
{
itsAge=age;
}
static int GetHowMany() //
{
return HowManyCats;
}
private:
int itsAge;
static int HowManyCats;
};
int Cat::HowManyCats=0;
int count()
{
cout<<"There are "<<Cat::GetHowMany()<<" Cats alive!\n";
}
int main()
{
const int MaxCats=5;
int i;
Cat *CatHouse[MaxCats];
for(i=0;i<MaxCats;i++)
{
CatHouse[i]=new Cat(i);
count();
}
for(i=0;i<MaxCats;i++)
{
delete CatHouse[i];
count();
}
return 0;
}
得到的结果均为:
3.初始化列表的初始化变量顺序是根据成员变量的声明顺序来执行的。
4.这个类声明正确吗?为什么?
class A
{
const int Size=0;
};
答案:不正确。
常量必须在构造函数的初始化列表里面初始化或者将其设置成static。
解析:可以参考C++成员变量初始化问题。
正确的程序可以为:
class A
{
static const int Size=0;
};
或者为:
class A
{
public:
A():Size(0)
{}
private:
const int Size;
};
5.析构函数可以是内联函数。
6.请看下面一段程序。
#include <iostream>
#include <string>
using namespace std;
class B
{
private:
int data;
public:
B()
{
cout<<"default constructor"<<endl;
}
~B()
{
cout<<"destructed"<<endl;
}
B(int i):data(i)
{
cout<<"constructed by parameter "<<data<<endl;
}
};
B Play(B b)
{
return b;
}
int main()
{
B temp=Play(5);
return 0;
}
问题:
(1)该程序输出的结果是什么?为什么会有这样的输出?
(2)B(int i):data(i),这种用法的专业术语叫什么?
(3)Play(5),形参类型是类,而5是个常量,这样写合法吗?为什么?
答案:
(1)输出的结果如下图所示:
constructed by parameter 5 //在Play(5)处,5通过隐含的类型转换调用了B::B(int i)
destructed //Play(5)返回时,参数的析构函数被调用
destructed //temp的析构函数调用:temp的构造函数调用的是编译器生成的拷贝构造函数,原来以为调用的是生成的赋值构造函数,结果查了下资料发现自己说错了,具体的解释见:拷贝构造函数与赋值构造函数,拷贝构造函数是在对象被创建时调用,而赋值构造函数只能被已经存在了的对象调用。
(2)带参数的构造函数,冒号后面是成员变量初始化列表(member initialization list)。
(3)合法。单个参数的构造函数如果不添加explicit关键字,会定义一个隐含的类型转换(从参数类型转换到自己的类类型);添加explicit关键字会消除这种隐含转换。
7.编写类String的构造函数、析构函数和赋值函数。
答案:
已知类String的原型为:
class String
{
public:
String(const char *str=NULL); // 构造函数
String(const String &other); // 拷贝构造函数
String& operator=(const String &other); // 赋值构造函数
~String(void); // 析构函数
private:
char *m_data; // 用于保存字符串
};
编写String的上述四个函数:
String::String(const char *str=NULL)
{
if(str==NULL)
{
m_data=new char[1];
m_data='\0';
}
else
{
int length=strlen(str);
m_data=new char[length+1];
strcpy(m_data, str);
}
}
String::String(const String &other)
{
int length=strlen(other.m_data);
m_data=new char[length+1];
strcpy(m_data, other.m_data);
}
Sting& String::operator=(const String &other)
{
if(this==&other)
return *this;
else
{
delete [] m_data;
int length=strlen(other.m_data);
m_data=new char[length+1];
strcpy(m_data, other.m_data);
return *this;
}
}
String::~String()
{
delete [] m_data;
}
8.重载是指编写一个与已有函数同名但是参数表不同(或许参数个数不同,或许参数类型不同,或许两者都不同)的函数。
9.若类中包含了需要深拷贝的字符指针,则需要编写拷贝构造函数与赋值构造函数。
10.以下代码的输出结果是什么?
#include <iostream>
using namespace std;
class A
{
protected:
int m_data;
public:
A(int data=0)
{
m_data=data;
}
int GetData()
{
return doGetData();
}
virtual int doGetData()
{
return m_data;
}
};
class B:public A
{
protected:
int m_data;
public:
B(int data=1)
{
m_data=data;
}
int doGetData()
{
return m_data;
}
};
class C:public B
{
protected:
int m_data;
public:
C(int data=2)
{
m_data=data;
}
};
int main()
{
C c(10);
cout<<c.GetData()<<endl;
cout<<c.A::GetData()<<endl;
cout<<c.B::GetData()<<endl;
cout<<c.C::GetData()<<endl;
cout<<c.doGetData()<<endl;
cout<<c.A::doGetData()<<endl;
cout<<c.B::doGetData()<<endl;
cout<<c.C::doGetData()<<endl;
system("PAUSE");
return 0;
}
答案:
其中c.A::doGetData()用到了覆盖虚函数机制,直接调用A中的doGetData()。
11.以下代码的输出结果是是什么?
#include <iostream>
using namespace std;
class A
{
public:
void virtual f()
{
cout<<"A"<<endl;
}
};
class B:public A
{
public:
void virtual f()
{
cout<<"B"<<endl;
}
};
int main()
{
A *pa= new A();
pa->f();
B *pb=(B*)pa;
pb->f();
delete pa, pb;
pa= new B();
pa->f();
pb=(B*)pa;
pb->f();
}
答案:
12.考虑A到J语句在编译时可能出现的情况,判断出各个语句的正确性。
#include <iostream>
class Parent
{
public:
Parent(int var=-1)
{
m_nPub=var;
m_nPtd=var;
m_nPrt=var;
}
public:
int m_nPub;
protected:
int m_nPtd;
private:
int m_nPrt;
};
class Child1:public Parent
{
public:
int GetPub(){return m_nPub;}
int GetPtd(){return m_nPtd;}
int GetPrt(){return m_nPrt;} //A
};
class Child2:protected Parent
{
public:
int GetPub(){return m_nPub;}
int GetPtd(){return m_nPtd;}
int GetPrt(){return m_nPrt;} //B
};
class Child3:private Parent
{
public:
int GetPub(){return m_nPub;}
int GetPtd(){return m_nPtd;}
int GetPrt(){return m_nPrt;} //C
};
int main()
{
Child1 cd1;
Child2 cd2;
Child3 cd3;
int nVar=0;
//public inherited
cd1.m_nPub=nVar;
//D
cd1.m_nPtd=nVar;
//E
nVar=cd1.GetPtd();
//F
//protected inherited
cd2.m_nPub=nVar;
//G
nVar=cd2.GetPtd();
//H
//private inherited
cd3.m_nPub=nVar;
//I
nVar=cd3.GetPtd();
//J
return 0;
}
答案:
A,B,C,E,G,I是“ERROR”。
D,F,H,J是“RIGHT”。
解析:参考:C++中private,public,protected的访问
13.下面程序的结果是什么?
#include <iostream>
using namespace std;
class A
{
char k[3];
public:
virtual void aa(){};
};
class B:public virtual A
{
char j[3];
public:
virtual void bb(){};
};
class C:public virtual B
{
char i[3];
public:
virtual void cc(){};
};
int main()
{
cout<<"sizeof(A): "<<sizeof(A)<<endl;
cout<<"sizeof(B): "<<sizeof(B)<<endl;
cout<<"sizeof(C): "<<sizeof(C)<<endl;
return 0;
}
答案:程序运行结果如下:
解析:涉及到C++中虚继承的问题。
虚拟继承是多重继承中特有的概念。虚拟基类是为解决多重继承而出现的。如下图所示。
类D继承自类B1、B2,而类B1、B2都继承自类A,因此出现如右图所示的局面(非虚基类)。为了节省内存空间,可以将B1、B2对A的继承定义为虚拟继承,而A就成了虚拟基类。最后形成如左图所示的情况。
实现的代码如下:
class A; //忽略C1和C2
class B1:public virtual A;
class B2:public virtual A;class D:public B1,public B2;
以sizeof(B)为例,sizeof(B)= char j[3]所占大小4 + 虚指针vfptr_B所占大小4 + sizeof(A)所占大小8 = 16
若不采用虚继承的方式而是直接继承,结果就不会产生偏移,结果为:
14.如果不指定public,C++默认的是私有继承。
15.Find the defects in each of the following programs, and explain why it is incorrect.
class base
{
private:
int i;
public:
base(int x){i=x;}
};
class derived:public base
{
private:
int i;
public:
derived(int x, int y){i=x;}
void printTotal()
{
int total=i+base::i;
}
};
答案:
1,派生类构造函数没有初始化基类成员变量值。2,派生类成员函数访问基类的私有成员。
修改如下:1,在派生类derived()构造函数中调用基类构造函数base()初始化基类成员变量i。2,讲派生类中成员i的访问标示符由private改为protected。
class base
{
protected:
int i;
public:
base(int x){i=x;}
};
class derived:public base
{
private:
int i;
public:
derived(int x, int y):base(x)
{
y=i;
}
void printTotal()
{
int total=i+base::i;
}
};
16.下面的程序有何错误?
#include <iostream>
using namespace std;
class Shape
{
public:
Shape(){}
~Shape(){}
virtual void Draw()=0;
};
int main()
{
Shape s1;
}
答案:因为Shape类中的Draw函数是一个纯虚函数,所以Shape为一个抽象类,故Shape不能实例化为一个对象。解决方法是将Draw函数改为一般的虚函数。