1. 请设计一个类,不能被拷贝
拷贝只会放生在两个场景中:拷贝构造函数以及赋值运算符重载,因此想要让一个类禁止拷贝,只需让该类不能调用拷贝构造函数以及赋值运算符重载即可。
用C++11的话,可以使用特殊的语法来实现一个不能被拷贝的类。在C++11中,可以使用删除函数(deleted function)来禁用拷贝构造函数和拷贝赋值运算符。
下面是使用C++11实现一个不能被拷贝的类的示例代码:
class NonCopyable {
public:
NonCopyable() {}
~NonCopyable() {}
// 删除拷贝构造函数和拷贝赋值运算符
NonCopyable(const NonCopyable&) = delete;
NonCopyable& operator=(const NonCopyable&) = delete;
};
在这个示例中,通过在拷贝构造函数和拷贝赋值运算符的声明后面加上= delete来删除这些函数。这样一来,当其他地方尝试拷贝或赋值这个类的对象时,编译器会报错。
这种方法更加简洁,也更符合现代C++的风格。同时,使用删除函数可以提供更明确的错误信息,让开发者更容易理解问题所在。
2. 请设计一个类,只能在堆上创建对象
实现方式:
- 将类的构造函数私有,拷贝构造声明成私有。防止别人调用拷贝在栈上生成对象。
- 提供一个静态的成员函数,在该静态成员函数中完成堆对象的创建
下面是一个示例代码,展示了如何设计一个只能在堆上创建对象的类:
class HeapOnly {
public:
static HeapOnly* createInstance() {
return new HeapOnly();
}
void destroyInstance() {
delete this;
}
// 禁用拷贝构造函数和拷贝赋值运算符
HeapOnly(const HeapOnly&) = delete;
HeapOnly& operator=(const HeapOnly&) = delete;
private:
HeapOnly() {}
~HeapOnly() {}
};
在这个示例中,HeapOnly类的构造函数和析构函数都是私有的,这样其他地方就无法直接创建或销毁HeapOnly类的对象。而通过静态成员函数createInstance(),可以在堆上创建一个HeapOnly对象,并返回指向该对象的指针。同时,destroyInstance()函数用于在堆上销毁HeapOnly对象。
此外,还禁用了拷贝构造函数和拷贝赋值运算符,以确保对象不能被拷贝。
使用这种设计,其他地方只能通过调用HeapOnly::createInstance()来创建对象,并且必须手动调用destroyInstance()来销毁对象。这样可以确保对象只能在堆上创建和销毁,而不能在栈上创建对象。
3. 请设计一个类,只能在栈上创建对象
这段代码定义了一个只能在栈上创建对象的类StackOnly。下面是对代码的解释:
class StackOnly {
public:
static StackOnly CreateObj()
{
return StackOnly();
}
void Print() const
{
cout << "StackOnly::Print()" << endl;
}
private:
StackOnly()
{}
StackOnly(const StackOnly&) = delete;
};
StackOnly类具有以下特点:
- 构造函数StackOnly()是私有的,因此无法直接在外部创建对象。
- 静态成员函数CreateObj()被用于在内部调用私有的构造函数,并返回一个StackOnly对象。
- 公有成员函数Print()用于打印一条消息。
在main()函数中,我们可以看到如何使用这个类:
int main()
{
StackOnly so1 = StackOnly::CreateObj();
so1.Print();
return 0;
}
在main()函数中,我们通过调用StackOnly::CreateObj()来创建一个StackOnly对象,并将其赋值给so1。然后,我们调用so1.Print()来打印一条消息。
请注意,由于构造函数是私有的,因此无法直接在栈上创建对象,如代码中注释所示。这是通过将构造函数声明为私有来实现的。
这样设计的目的是确保只能通过特定的方式创建对象,以强制对对象的创建进行控制。
4. 单例模式
4.1. 饿汉模式
在C++中,饿汉模式(Eager Singleton)是一种单例设计模式的实现方式。单例模式是一种创建型设计模式,它确保一个类只有一个实例,并提供一个全局访问点来访问该实例。
饿汉模式的特点是在程序启动时就创建单例实例,并在整个程序的生命周期内保持不变。这意味着无论是否使用该实例,它都会被创建并占用内存。
class InfoSingleton
{
public:
static InfoSingleton& GetInstance()
{
return _sins;
}
void Insert(string name, int salary)
{
_info[name] = salary;
}
void Print()
{
for (auto kv : _info)
{
cout << kv.first << ":" << kv.second << endl;
}
cout << endl;
}
private:
InfoSingleton()
{}
InfoSingleton(const InfoSingleton& info) = delete;
InfoSingleton& operator=(const InfoSingleton& info) = delete;
map<string, int> _info;
// ...
private:
static InfoSingleton _sins;
};
InfoSingleton InfoSingleton::_sins;
int main()
{
InfoSingleton::GetInstance().Insert("张三", 10000);
InfoSingleton& infosl = InfoSingleton::GetInstance();
infosl.Insert("李四", 15000);
infosl.Insert("赵六", 12000);
infosl.Insert("王五", 8000);
infosl.Print();
// ...
return 0;
}
在这个例子中,InfoSingleton类是一个单例类。以下是饿汉模式的关键点:
- 类中的静态成员变量_sins是InfoSingleton类的唯一实例。
- **GetInstance()**是一个静态成员函数,用于获取单例实例。它返回一个引用,以便可以对单例实例进行操作。
- **构造函数****InfoSingleton()**是私有的,因此无法直接在外部创建对象。这样做是为了防止在程序中的其他地方创建多个实例。
- 复制构造函数和赋值运算符被删除,以防止通过复制或赋值操作创建多个实例。
- 在类定义之外,我们在全局范围内创建了一个InfoSingleton对象_sins,这样它就会在程序启动时被创建。
通过调用InfoSingleton::GetInstance(),我们可以获取对单例实例的引用,并对其进行操作。在您的代码中,我们使用InfoSingleton::GetInstance()来插入和打印员工信息。
饿汉模式的优点是实现简单,线程安全(因为实例在程序启动时就已经创建),并且可以保证全局唯一性。然而,它的缺点是可能会浪费内存,因为实例在整个程序的生命周期内都存在,即使不使用它。
4.2. 懒汉模式
在C++中,懒汉模式(Lazy Singleton)是一种单例设计模式的实现方式。与饿汉模式不同,懒汉模式在第一次使用时才创建单例实例。
class InfoSingleton
{
public:
static InfoSingleton& GetInstance()
{
static InfoSingleton sinst;
return sinst;
}
void Insert(string name, int salary)
{
_info[name] = salary;
}
void Print()
{
for (auto kv : _info)
{
cout << kv.first << ":" << kv.second << endl;
}
cout << endl;
}
private:
InfoSingleton()
{
cout << "InfoSingleton()" << endl;
}
InfoSingleton(const InfoSingleton& info) = delete;
InfoSingleton& operator=(const InfoSingleton& info) = delete;
map<string, int> _info;
// ...
};
int main()
{
infosingleton::getinstance().insert("张三", 10000);
infosingleton& infosl = infosingleton::getinstance();
infosl.insert("李四", 15000);
infosl.insert("赵六", 12000);
infosl.insert("王五", 8000);
infosl.print();
infosingleton::getinstance().insert("张三", 13000);
infosingleton::getinstance().print();
infosl.print();
return 0;
}
在这个例子中,InfoSingleton类是一个单例类。以下是懒汉模式的关键点:
- 类中的静态局部变量sinst是InfoSingleton类的唯一实例。它是在GetInstance()函数内部定义的,所以它的创建会被延迟到第一次调用GetInstance()时。
- GetInstance()是一个静态成员函数,用于获取单例实例。它返回一个引用,以便可以对单例实例进行操作。
- **构造函数****InfoSingleton()**是私有的,因此无法直接在外部创建对象。这样做是为了防止在程序中的其他地方创建多个实例。
- 复制构造函数和赋值运算符被删除,以防止通过复制或赋值操作创建多个实例。
- 在类定义之外,我们在GetInstance()函数内部创建了一个InfoSingleton对象sinst,这样它就会在第一次调用GetInstance()时被创建。
**懒汉模式的优点是实现简单,并且在第一次使用时才会创建实例,避免了可能的内存浪费。**然而,懒汉模式在多线程环境下可能存在线程安全问题。在C++11之前,静态局部变量的初始化是非线程安全的。但是在C++11之后,编译器保证了静态局部变量的线程安全性,因此可以在多线程环境下使用懒汉模式。
4.3. 懒汉模式和饿汉模式的区别
懒汉模式和饿汉模式在返回单例对象的函数上是相似的,都是返回一个静态的对象。但是它们的实现方式有所不同。
- **在懒汉模式中,单例对象在第一次使用时才被创建。**这意味着在调用获取单例对象的函数之前,单例对象并不存在。当第一次调用获取单例对象的函数时,会创建一个静态局部变量,该静态局部变量是单例对象,并且在整个程序运行期间只会创建一次。
- **而在饿汉模式中,单例对象在程序启动时就被创建。**这意味着单例对象在整个程序运行期间都是存在的,无论是否使用它。饿汉模式的实现方式是在类定义中直接创建一个静态成员变量,并在该变量的定义处初始化单例对象。
懒汉模式和饿汉模式是两种常见的单例模式实现方式,它们的区别主要体现在单例对象的创建时机和线程安全性上。文章来源:https://www.toymoban.com/news/detail-682987.html
- 创建时机:
-
- 懒汉模式:单例对象在第一次使用时才会被创建。在获取单例对象的函数中,会检查单例对象是否已经创建,如果没有则创建一个新的对象并返回。
- 饿汉模式:单例对象在程序启动时就会被创建。在类定义中直接创建一个静态成员变量,并在该变量的定义处进行初始化。
- 线程安全性:
-
- 懒汉模式:在多线程环境下,懒汉模式可能存在线程安全问题。如果多个线程同时调用获取单例对象的函数,并且单例对象尚未创建,那么可能会创建多个实例。为了解决这个问题,可以使用互斥锁等机制来保证线程安全。
- 饿汉模式:饿汉模式在程序启动时就创建了单例对象,因此不存在线程安全问题。在多线程环境下,无论多少个线程同时调用获取单例对象的函数,都只会返回同一个已经创建好的对象。
选择懒汉模式还是饿汉模式取决于具体的需求和场景。懒汉模式的优点是实现简单,且只在需要时才会创建对象,节省了内存资源。但是需要注意处理多线程环境下的线程安全问题。饿汉模式的优点是线程安全,不需要额外的线程同步机制,但在程序启动时就会创建对象,可能会造成一定的资源浪费。文章来源地址https://www.toymoban.com/news/detail-682987.html
到了这里,关于【高级程序设计语言C++】特殊类设计的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!